LCOV - code coverage report
Current view: top level - lib/ring - soring.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 117 145 80.7 %
Date: 2025-05-01 17:49:45 Functions: 14 16 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 112 400 28.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2024 Huawei Technologies Co., Ltd
       3                 :            :  */
       4                 :            : 
       5                 :            : /**
       6                 :            :  * @file
       7                 :            :  * This file contains implementation of SORING 'datapath' functions.
       8                 :            :  *
       9                 :            :  * Brief description:
      10                 :            :  * ==================
      11                 :            :  * enqueue/dequeue works the same as for conventional rte_ring:
      12                 :            :  * any rte_ring sync types can be used, etc.
      13                 :            :  * Plus there could be multiple 'stages'.
      14                 :            :  * For each stage there is an acquire (start) and release (finish) operation.
      15                 :            :  * After some elems are 'acquired' - user can safely assume that he has
      16                 :            :  * exclusive possession of these elems till 'release' for them is done.
      17                 :            :  * Note that right now user has to release exactly the same number of elems
      18                 :            :  * he acquired before.
      19                 :            :  * After 'release', elems can be 'acquired' by next stage and/or dequeued
      20                 :            :  * (in case of last stage).
      21                 :            :  *
      22                 :            :  * Internal structure:
      23                 :            :  * ===================
      24                 :            :  * In addition to 'normal' ring of elems, it also has a ring of states of the
      25                 :            :  * same size. Each state[] corresponds to exactly one elem[].
      26                 :            :  * state[] will be used by acquire/release/dequeue functions to store internal
      27                 :            :  * information and should not be accessed by the user directly.
      28                 :            :  *
      29                 :            :  * How it works:
      30                 :            :  * =============
      31                 :            :  * 'acquire()' just moves stage's head (same as rte_ring move_head does),
      32                 :            :  * plus it saves in state[stage.cur_head] information about how many elems
      33                 :            :  * were acquired, current head position and special flag value to indicate
      34                 :            :  * that elems are acquired (SORING_ST_START).
      35                 :            :  * Note that 'acquire()' returns to the user a special 'ftoken' that user has
      36                 :            :  * to provide for 'release()' (in fact it is just a position for current head
      37                 :            :  * plus current stage index).
      38                 :            :  * 'release()' extracts old head value from provided ftoken and checks that
      39                 :            :  * corresponding 'state[]' contains expected values(mostly for sanity
      40                 :            :  * purposes).
      41                 :            :  * Then it marks this state[] with 'SORING_ST_FINISH' flag to indicate
      42                 :            :  * that given subset of objects was released.
      43                 :            :  * After that, it checks does old head value equals to current tail value?
      44                 :            :  * If yes, then it performs  'finalize()' operation, otherwise 'release()'
      45                 :            :  * just returns (without spinning on stage tail value).
      46                 :            :  * As updated state[] is shared by all threads, some other thread can do
      47                 :            :  * 'finalize()' for given stage.
      48                 :            :  * That allows 'release()' to avoid excessive waits on the tail value.
      49                 :            :  * Main purpose of 'finalize()' operation is to walk through 'state[]'
      50                 :            :  * from current stage tail up to its head, check state[] and move stage tail
      51                 :            :  * through elements that already are in SORING_ST_FINISH state.
      52                 :            :  * Along with that, corresponding state[] values are reset to zero.
      53                 :            :  * Note that 'finalize()' for given stage can be done from multiple places:
      54                 :            :  * 'release()' for that stage or from 'acquire()' for next stage
      55                 :            :  * even from consumer's 'dequeue()' - in case given stage is the last one.
      56                 :            :  * So 'finalize()' has to be MT-safe and inside it we have to
      57                 :            :  * guarantee that only one thread will update state[] and stage's tail values.
      58                 :            :  */
      59                 :            : 
      60                 :            : #include "soring.h"
      61                 :            : 
      62                 :            : #include <eal_export.h>
      63                 :            : 
      64                 :            : /*
      65                 :            :  * Inline functions (fastpath) start here.
      66                 :            :  */
      67                 :            : static __rte_always_inline uint32_t
      68                 :            : __rte_soring_stage_finalize(struct soring_stage_headtail *sht, uint32_t stage,
      69                 :            :         union soring_state *rstate, uint32_t rmask, uint32_t maxn)
      70                 :            : {
      71                 :            :         int32_t rc;
      72                 :            :         uint32_t ftkn, head, i, idx, k, n, tail;
      73                 :            :         union soring_stage_tail nt, ot;
      74                 :            :         union soring_state st;
      75                 :            : 
      76                 :            :         /* try to grab exclusive right to update tail value */
      77                 :      20010 :         ot.raw = rte_atomic_load_explicit(&sht->tail.raw,
      78                 :            :                         rte_memory_order_acquire);
      79                 :            : 
      80                 :            :         /* other thread already finalizing it for us */
      81                 :      20010 :         if (ot.sync != 0)
      82                 :            :                 return 0;
      83                 :            : 
      84                 :      20010 :         nt.pos = ot.pos;
      85                 :      20010 :         nt.sync = 1;
      86                 :      20010 :         rc = rte_atomic_compare_exchange_strong_explicit(&sht->tail.raw,
      87                 :            :                 (uint64_t *)(uintptr_t)&ot.raw, nt.raw,
      88                 :            :                 rte_memory_order_release, rte_memory_order_relaxed);
      89                 :            : 
      90                 :            :         /* other thread won the race */
      91   [ +  -  +  -  :      20010 :         if (rc == 0)
          -  -  -  -  -  
          -  -  -  -  -  
          +  -  -  -  +  
                      - ]
      92                 :            :                 return 0;
      93                 :            : 
      94                 :            :         /* Ensure the head is read before rstate[] */
      95                 :      20010 :         head = rte_atomic_load_explicit(&sht->head, rte_memory_order_relaxed);
      96                 :            :         rte_atomic_thread_fence(rte_memory_order_acquire);
      97                 :            : 
      98                 :            :         /*
      99                 :            :          * start with current tail and walk through states that are
     100                 :            :          * already finished.
     101                 :            :          */
     102                 :            : 
     103                 :      20010 :         n = RTE_MIN(head - ot.pos, maxn);
     104   [ +  +  +  +  :      30015 :         for (i = 0, tail = ot.pos; i < n; i += k, tail += k) {
          -  -  -  -  -  
          -  -  -  -  -  
          -  +  -  -  -  
                      + ]
     105                 :            : 
     106                 :      10005 :                 idx = tail & rmask;
     107                 :      10005 :                 ftkn = SORING_FTKN_MAKE(tail, stage);
     108                 :            : 
     109                 :      10005 :                 st.raw = rte_atomic_load_explicit(&rstate[idx].raw,
     110                 :            :                         rte_memory_order_relaxed);
     111   [ +  -  +  -  :      10005 :                 if ((st.stnum & SORING_ST_MASK) != SORING_ST_FINISH ||
          +  -  +  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                      - ]
     112                 :            :                                 st.ftoken != ftkn)
     113                 :            :                         break;
     114                 :            : 
     115                 :      10005 :                 k = st.stnum & ~SORING_ST_MASK;
     116                 :      10005 :                 rte_atomic_store_explicit(&rstate[idx].raw, 0,
     117                 :            :                                 rte_memory_order_relaxed);
     118                 :            :         }
     119                 :            : 
     120                 :            : 
     121                 :            :         /* release exclusive right to update along with new tail value */
     122                 :      20010 :         ot.pos = tail;
     123                 :      20010 :         rte_atomic_store_explicit(&sht->tail.raw, ot.raw,
     124                 :            :                         rte_memory_order_release);
     125                 :            : 
     126                 :      20010 :         return i;
     127                 :            : }
     128                 :            : 
     129                 :            : static __rte_always_inline uint32_t
     130                 :            : __rte_soring_move_prod_head(struct rte_soring *r, uint32_t num,
     131                 :            :         enum rte_ring_queue_behavior behavior, enum rte_ring_sync_type st,
     132                 :            :         uint32_t *head, uint32_t *next, uint32_t *free)
     133                 :            : {
     134                 :            :         uint32_t n;
     135                 :            : 
     136                 :          6 :         switch (st) {
     137                 :          6 :         case RTE_RING_SYNC_ST:
     138                 :            :         case RTE_RING_SYNC_MT:
     139                 :          6 :                 n = __rte_ring_headtail_move_head(&r->prod.ht, &r->cons.ht,
     140                 :            :                         r->capacity, st, num, behavior, head, next, free);
     141                 :            :                 break;
     142                 :          0 :         case RTE_RING_SYNC_MT_RTS:
     143                 :          0 :                 n = __rte_ring_rts_move_head(&r->prod.rts, &r->cons.ht,
     144                 :            :                         r->capacity, num, behavior, head, free);
     145                 :          0 :                 *next = *head + n;
     146                 :          0 :                 break;
     147                 :          0 :         case RTE_RING_SYNC_MT_HTS:
     148                 :          0 :                 n = __rte_ring_hts_move_head(&r->prod.hts, &r->cons.ht,
     149                 :            :                         r->capacity, num, behavior, head, free);
     150                 :          0 :                 *next = *head + n;
     151                 :          0 :                 break;
     152                 :            :         default:
     153                 :            :                 /* unsupported mode, shouldn't be here */
     154                 :            :                 RTE_ASSERT(0);
     155                 :            :                 *free = 0;
     156                 :            :                 n = 0;
     157                 :            :         }
     158                 :            : 
     159                 :            :         return n;
     160                 :            : }
     161                 :            : 
     162                 :            : static __rte_always_inline uint32_t
     163                 :            : __rte_soring_move_cons_head(struct rte_soring *r, uint32_t stage, uint32_t num,
     164                 :            :         enum rte_ring_queue_behavior behavior, enum rte_ring_sync_type st,
     165                 :            :         uint32_t *head, uint32_t *next, uint32_t *avail)
     166                 :            : {
     167                 :            :         uint32_t n;
     168                 :            : 
     169   [ -  -  -  -  :          3 :         switch (st) {
          +  -  -  -  -  
          -  -  -  -  -  
                   -  - ]
     170                 :      10011 :         case RTE_RING_SYNC_ST:
     171                 :            :         case RTE_RING_SYNC_MT:
     172                 :            :                 n = __rte_ring_headtail_move_head(&r->cons.ht,
     173                 :      10011 :                         &r->stage[stage].ht, 0, st, num, behavior,
     174                 :            :                         head, next, avail);
     175                 :            :                 break;
     176                 :          0 :         case RTE_RING_SYNC_MT_RTS:
     177                 :          0 :                 n = __rte_ring_rts_move_head(&r->cons.rts, &r->stage[stage].ht,
     178                 :            :                         0, num, behavior, head, avail);
     179                 :          0 :                 *next = *head + n;
     180                 :          0 :                 break;
     181                 :          0 :         case RTE_RING_SYNC_MT_HTS:
     182                 :          0 :                 n = __rte_ring_hts_move_head(&r->cons.hts, &r->stage[stage].ht,
     183                 :            :                         0, num, behavior, head, avail);
     184                 :          0 :                 *next = *head + n;
     185                 :          0 :                 break;
     186                 :            :         default:
     187                 :            :                 /* unsupported mode, shouldn't be here */
     188                 :            :                 RTE_ASSERT(0);
     189                 :            :                 *avail = 0;
     190                 :            :                 n = 0;
     191                 :            :         }
     192                 :            : 
     193                 :            :         return n;
     194                 :            : }
     195                 :            : 
     196                 :            : static __rte_always_inline void
     197                 :            : __rte_soring_update_tail(struct __rte_ring_headtail *rht,
     198                 :            :         enum rte_ring_sync_type st, uint32_t head, uint32_t next, uint32_t enq)
     199                 :            : {
     200                 :            :         uint32_t n;
     201                 :            : 
     202   [ +  -  -  -  :          9 :         switch (st) {
          +  -  -  -  +  
          -  -  -  -  -  
          -  -  +  -  -  
          -  +  -  -  -  
          -  -  -  -  -  
                -  -  - ]
     203                 :            :         case RTE_RING_SYNC_ST:
     204                 :            :         case RTE_RING_SYNC_MT:
     205                 :            :                 __rte_ring_update_tail(&rht->ht, head, next, st, enq);
     206                 :            :                 break;
     207                 :          0 :         case RTE_RING_SYNC_MT_RTS:
     208                 :            :                 __rte_ring_rts_update_tail(&rht->rts);
     209                 :            :                 break;
     210                 :          0 :         case RTE_RING_SYNC_MT_HTS:
     211                 :            :                 n = next - head;
     212                 :            :                 __rte_ring_hts_update_tail(&rht->hts, head, n, enq);
     213                 :            :                 break;
     214                 :            :         default:
     215                 :            :                 /* unsupported mode, shouldn't be here */
     216                 :            :                 RTE_ASSERT(0);
     217                 :            :         }
     218                 :            : }
     219                 :            : 
     220                 :            : static __rte_always_inline uint32_t
     221                 :            : __rte_soring_stage_move_head(struct soring_stage_headtail *d,
     222                 :            :         const struct rte_ring_headtail *s, uint32_t capacity, uint32_t num,
     223                 :            :         enum rte_ring_queue_behavior behavior,
     224                 :            :         uint32_t *old_head, uint32_t *new_head, uint32_t *avail)
     225                 :            : {
     226                 :            :         uint32_t n, tail;
     227                 :            : 
     228                 :          5 :         *old_head = rte_atomic_load_explicit(&d->head,
     229                 :            :                         rte_memory_order_relaxed);
     230                 :            : 
     231                 :            :         do {
     232                 :            :                 n = num;
     233                 :            : 
     234                 :            :                 /* Ensure the head is read before tail */
     235                 :            :                 rte_atomic_thread_fence(rte_memory_order_acquire);
     236                 :            : 
     237                 :      10005 :                 tail = rte_atomic_load_explicit(&s->tail,
     238                 :            :                                 rte_memory_order_acquire);
     239                 :      10005 :                 *avail = capacity + tail - *old_head;
     240   [ +  -  -  -  :      10003 :                 if (n > *avail)
          +  -  +  -  -  
          -  +  -  -  -  
                   -  - ]
     241                 :            :                         n = (behavior == RTE_RING_QUEUE_FIXED) ? 0 : *avail;
     242   [ +  -  +  -  :      10005 :                 if (n == 0)
          -  -  -  -  -  
          -  -  -  +  -  
          +  -  -  -  +  
             -  -  -  -  
                      - ]
     243                 :            :                         return 0;
     244                 :      10005 :                 *new_head = *old_head + n;
     245                 :      10005 :         } while (rte_atomic_compare_exchange_strong_explicit(&d->head,
     246                 :            :                         old_head, *new_head, rte_memory_order_acq_rel,
     247   [ -  +  -  +  :      10005 :                         rte_memory_order_relaxed) == 0);
          -  -  -  -  -  
          -  -  -  -  +  
          -  +  -  -  -  
             +  -  -  -  
                      - ]
     248                 :            : 
     249                 :            :         return n;
     250                 :            : }
     251                 :            : 
     252                 :            : static __rte_always_inline uint32_t
     253                 :            : soring_enqueue(struct rte_soring *r, const void *objs,
     254                 :            :         const void *meta, uint32_t n, enum rte_ring_queue_behavior behavior,
     255                 :            :         uint32_t *free_space)
     256                 :            : {
     257                 :            :         enum rte_ring_sync_type st;
     258                 :            :         uint32_t nb_free, prod_head, prod_next;
     259                 :            : 
     260                 :            :         RTE_ASSERT(r != NULL && r->nb_stage > 0);
     261                 :            :         RTE_ASSERT(meta == NULL || r->meta != NULL);
     262                 :            : 
     263                 :          6 :         st = r->prod.ht.sync_type;
     264                 :            : 
     265                 :            :         n = __rte_soring_move_prod_head(r, n, behavior, st,
     266                 :            :                         &prod_head, &prod_next, &nb_free);
     267   [ +  -  +  -  :          6 :         if (n != 0) {
             -  -  -  + ]
     268                 :          5 :                 __rte_ring_do_enqueue_elems(&r[1], objs, r->size,
     269   [ -  +  +  +  :          5 :                         prod_head & r->mask, r->esize, n);
             -  -  -  - ]
     270   [ +  -  -  - ]:          2 :                 if (meta != NULL)
     271                 :          2 :                         __rte_ring_do_enqueue_elems(r->meta, meta, r->size,
     272   [ -  +  -  - ]:          2 :                                 prod_head & r->mask, r->msize, n);
     273                 :            :                 __rte_soring_update_tail(&r->prod, st, prod_head, prod_next, 1);
     274                 :            :         }
     275                 :            : 
     276   [ +  +  +  -  :          6 :         if (free_space != NULL)
             -  -  +  - ]
     277                 :          5 :                 *free_space = nb_free - n;
     278                 :            :         return n;
     279                 :            : }
     280                 :            : 
     281                 :            : static __rte_always_inline uint32_t
     282                 :            : soring_dequeue(struct rte_soring *r, void *objs, void *meta,
     283                 :            :         uint32_t num, enum rte_ring_queue_behavior behavior,
     284                 :            :         uint32_t *available)
     285                 :            : {
     286                 :            :         enum rte_ring_sync_type st;
     287                 :            :         uint32_t entries, cons_head, cons_next, n, ns, reqn;
     288                 :            : 
     289                 :            :         RTE_ASSERT(r != NULL && r->nb_stage > 0);
     290                 :            :         RTE_ASSERT(meta == NULL || r->meta != NULL);
     291                 :            : 
     292                 :      10008 :         ns = r->nb_stage - 1;
     293                 :      10008 :         st = r->cons.ht.sync_type;
     294                 :            : 
     295                 :            :         /* try to grab exactly @num elems first */
     296                 :            :         n = __rte_soring_move_cons_head(r, ns, num, RTE_RING_QUEUE_FIXED, st,
     297                 :            :                         &cons_head, &cons_next, &entries);
     298   [ -  +  +  +  :      10008 :         if (n == 0) {
             -  +  +  - ]
     299                 :            :                 /* try to finalize some elems from previous stage */
     300   [ -  -  +  -  :      10005 :                 n = __rte_soring_stage_finalize(&r->stage[ns].sht, ns,
             -  -  +  - ]
     301                 :            :                         r->state, r->mask, 2 * num);
     302                 :      10002 :                 entries += n;
     303                 :            : 
     304                 :            :                 /* repeat attempt to grab elems */
     305                 :            :                 reqn = (behavior == RTE_RING_QUEUE_FIXED) ? num : 0;
     306   [ -  -  -  + ]:      10002 :                 if (entries >= reqn)
     307                 :            :                         n = __rte_soring_move_cons_head(r, ns, num, behavior,
     308                 :            :                                 st, &cons_head, &cons_next, &entries);
     309                 :            :                 else
     310                 :            :                         n = 0;
     311                 :            :         }
     312                 :            : 
     313                 :            :         /* we have some elems to consume */
     314   [ +  -  +  +  :      10008 :         if (n != 0) {
             +  -  -  + ]
     315                 :          4 :                 __rte_ring_do_dequeue_elems(objs, &r[1], r->size,
     316   [ -  +  +  -  :          4 :                         cons_head & r->mask, r->esize, n);
             -  +  -  - ]
     317   [ +  -  +  - ]:          2 :                 if (meta != NULL)
     318                 :          2 :                         __rte_ring_do_dequeue_elems(meta, r->meta, r->size,
     319   [ -  +  -  + ]:          2 :                                 cons_head & r->mask, r->msize, n);
     320                 :            :                 __rte_soring_update_tail(&r->cons, st, cons_head, cons_next, 0);
     321                 :            :         }
     322                 :            : 
     323   [ -  +  -  +  :      10008 :         if (available != NULL)
             -  +  -  + ]
     324                 :          0 :                 *available = entries - n;
     325                 :            :         return n;
     326                 :            : }
     327                 :            : 
     328                 :            : /*
     329                 :            :  * Verify internal SORING state.
     330                 :            :  * WARNING: if expected value is not equal to actual one, it means that for
     331                 :            :  * whatever reason SORING data constancy is broken. That is a very serious
     332                 :            :  * problem that most likely will cause race-conditions, memory corruption,
     333                 :            :  * program crash.
     334                 :            :  * To ease debugging it user might rebuild ring library with
     335                 :            :  * RTE_SORING_DEBUG enabled.
     336                 :            :  */
     337                 :            : static __rte_always_inline void
     338                 :            : soring_verify_state(const struct rte_soring *r, uint32_t stage, uint32_t idx,
     339                 :            :         const char *msg, union soring_state val,  union soring_state exp)
     340                 :            : {
     341                 :      20010 :         if (val.raw != exp.raw) {
     342                 :            : #ifdef RTE_SORING_DEBUG
     343                 :            :                 rte_soring_dump(stderr, r);
     344                 :            :                 rte_panic("line:%d from:%s: soring=%p, stage=%#x, idx=%#x, "
     345                 :            :                         "expected={.stnum=%#x, .ftoken=%#x}, "
     346                 :            :                         "actual={.stnum=%#x, .ftoken=%#x};\n",
     347                 :            :                         __LINE__, msg, r, stage, idx,
     348                 :            :                         exp.stnum, exp.ftoken,
     349                 :            :                         val.stnum, val.ftoken);
     350                 :            : #else
     351                 :          0 :                 SORING_LOG(EMERG, "from:%s: soring=%p, stage=%#x, idx=%#x, "
     352                 :            :                         "expected={.stnum=%#x, .ftoken=%#x}, "
     353                 :            :                         "actual={.stnum=%#x, .ftoken=%#x};",
     354                 :            :                         msg, r, stage, idx,
     355                 :            :                         exp.stnum, exp.ftoken,
     356                 :            :                         val.stnum, val.ftoken);
     357                 :            : #endif
     358                 :            :         }
     359                 :            : }
     360                 :            : 
     361                 :            : /* check and update state ring at acquire op*/
     362                 :            : static __rte_always_inline void
     363                 :            : acquire_state_update(const struct rte_soring *r, uint32_t stage, uint32_t idx,
     364                 :            :         uint32_t ftoken, uint32_t num)
     365                 :            : {
     366                 :            :         union soring_state st;
     367                 :            :         const union soring_state est = {.raw = 0};
     368                 :            : 
     369                 :      10005 :         st.raw = rte_atomic_load_explicit(&r->state[idx].raw,
     370                 :            :                         rte_memory_order_relaxed);
     371                 :            :         soring_verify_state(r, stage, idx, __func__, st, est);
     372                 :            : 
     373                 :      10005 :         st.ftoken = ftoken;
     374                 :      10005 :         st.stnum = (SORING_ST_START | num);
     375                 :            : 
     376                 :      10005 :         rte_atomic_store_explicit(&r->state[idx].raw, st.raw,
     377                 :            :                         rte_memory_order_relaxed);
     378                 :            : }
     379                 :            : 
     380                 :            : static __rte_always_inline uint32_t
     381                 :            : soring_acquire(struct rte_soring *r, void *objs, void *meta,
     382                 :            :         uint32_t stage, uint32_t num, enum rte_ring_queue_behavior behavior,
     383                 :            :         uint32_t *ftoken, uint32_t *available)
     384                 :            : {
     385                 :            :         uint32_t avail, head, idx, n, next, reqn;
     386                 :            :         struct soring_stage *pstg;
     387                 :            :         struct soring_stage_headtail *cons;
     388                 :            : 
     389                 :            :         RTE_ASSERT(r != NULL && stage < r->nb_stage);
     390                 :            :         RTE_ASSERT(meta == NULL || r->meta != NULL);
     391                 :            : 
     392                 :      10005 :         cons = &r->stage[stage].sht;
     393                 :            : 
     394                 :      10005 :         if (stage == 0)
     395                 :            :                 n = __rte_soring_stage_move_head(cons, &r->prod.ht, 0, num,
     396                 :            :                         behavior, &head, &next, &avail);
     397                 :            :         else {
     398                 :      10000 :                 pstg = r->stage + stage - 1;
     399                 :            : 
     400                 :            :                 /* try to grab exactly @num elems */
     401                 :            :                 n = __rte_soring_stage_move_head(cons, &pstg->ht, 0, num,
     402                 :            :                         RTE_RING_QUEUE_FIXED, &head, &next, &avail);
     403   [ -  +  -  -  :      10000 :                 if (n == 0) {
             -  +  -  - ]
     404                 :            :                         /* try to finalize some elems from previous stage */
     405   [ #  #  #  #  :          0 :                         n = __rte_soring_stage_finalize(&pstg->sht, stage - 1,
             #  #  #  # ]
     406                 :            :                                 r->state, r->mask, 2 * num);
     407                 :          0 :                         avail += n;
     408                 :            : 
     409                 :            :                         /* repeat attempt to grab elems */
     410                 :            :                         reqn = (behavior == RTE_RING_QUEUE_FIXED) ? num : 0;
     411   [ #  #  #  # ]:          0 :                         if (avail >= reqn)
     412                 :            :                                 n = __rte_soring_stage_move_head(cons,
     413                 :            :                                         &pstg->ht, 0, num, behavior, &head,
     414                 :            :                                         &next, &avail);
     415                 :            :                         else
     416                 :            :                                 n = 0;
     417                 :            :                 }
     418                 :            :         }
     419                 :            : 
     420   [ +  -  -  -  :      10005 :         if (n != 0) {
             +  -  +  - ]
     421                 :            : 
     422                 :      10005 :                 idx = head & r->mask;
     423   [ -  +  -  -  :      10005 :                 *ftoken = SORING_FTKN_MAKE(head, stage);
             -  +  -  + ]
     424                 :            : 
     425                 :            :                 /* check and update state value */
     426                 :            :                 acquire_state_update(r, stage, idx, *ftoken, n);
     427                 :            : 
     428                 :            :                 /* copy elems that are ready for given stage */
     429   [ -  +  -  -  :      10005 :                 __rte_ring_do_dequeue_elems(objs, &r[1], r->size, idx,
             -  +  +  - ]
     430                 :            :                                 r->esize, n);
     431   [ +  -  +  - ]:      10003 :                 if (meta != NULL)
     432   [ -  +  -  + ]:      10003 :                         __rte_ring_do_dequeue_elems(meta, r->meta,
     433                 :            :                                 r->size, idx, r->msize, n);
     434                 :            :         }
     435                 :            : 
     436   [ -  +  -  -  :      10005 :         if (available != NULL)
             -  +  -  + ]
     437                 :          0 :                 *available = avail - n;
     438                 :            :         return n;
     439                 :            : }
     440                 :            : 
     441                 :            : static __rte_always_inline void
     442                 :            : soring_release(struct rte_soring *r, const void *objs,
     443                 :            :         const void *meta, uint32_t stage, uint32_t n, uint32_t ftoken)
     444                 :            : {
     445                 :            :         uint32_t idx, pos, tail;
     446                 :            :         struct soring_stage *stg;
     447                 :            :         union soring_state st;
     448                 :            : 
     449                 :            :         const union soring_state est = {
     450                 :      10005 :                 .stnum = (SORING_ST_START | n),
     451                 :            :                 .ftoken = ftoken,
     452                 :            :         };
     453                 :            : 
     454                 :            :         RTE_ASSERT(r != NULL && stage < r->nb_stage);
     455                 :            :         RTE_ASSERT(meta == NULL || r->meta != NULL);
     456                 :            : 
     457                 :      10005 :         stg = r->stage + stage;
     458                 :            : 
     459                 :      10005 :         pos = SORING_FTKN_POS(ftoken, stage);
     460                 :      10005 :         idx = pos & r->mask;
     461                 :      10005 :         st.raw = rte_atomic_load_explicit(&r->state[idx].raw,
     462                 :            :                         rte_memory_order_relaxed);
     463                 :            : 
     464                 :            :         /* check state ring contents */
     465                 :      10005 :         soring_verify_state(r, stage, idx, __func__, st, est);
     466                 :            : 
     467                 :            :         /* update contents of the ring, if necessary */
     468   [ +  +  -  + ]:      10005 :         if (objs != NULL)
     469   [ -  +  -  - ]:      10000 :                 __rte_ring_do_enqueue_elems(&r[1], objs, r->size, idx,
     470                 :            :                         r->esize, n);
     471         [ +  - ]:      10001 :         if (meta != NULL)
     472         [ -  + ]:      10001 :                 __rte_ring_do_enqueue_elems(r->meta, meta, r->size, idx,
     473                 :            :                         r->msize, n);
     474                 :            : 
     475                 :            :         /* set state to FINISH, make sure it is not reordered */
     476                 :            :         rte_atomic_thread_fence(rte_memory_order_release);
     477                 :            : 
     478                 :      10005 :         st.stnum = SORING_ST_FINISH | n;
     479                 :      10005 :         rte_atomic_store_explicit(&r->state[idx].raw, st.raw,
     480                 :            :                         rte_memory_order_relaxed);
     481                 :            : 
     482                 :            :         /* try to do finalize(), if appropriate */
     483                 :      10005 :         tail = rte_atomic_load_explicit(&stg->sht.tail.pos,
     484                 :            :                         rte_memory_order_relaxed);
     485   [ +  -  +  - ]:      10005 :         if (tail == pos)
     486   [ +  -  +  - ]:      10005 :                 __rte_soring_stage_finalize(&stg->sht, stage, r->state, r->mask,
     487                 :            :                                 r->capacity);
     488                 :            : }
     489                 :            : 
     490                 :            : /*
     491                 :            :  * Public functions (data-path) start here.
     492                 :            :  */
     493                 :            : 
     494                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_release, 25.03)
     495                 :            : void
     496         [ -  + ]:          4 : rte_soring_release(struct rte_soring *r, const void *objs,
     497                 :            :         uint32_t stage, uint32_t n, uint32_t ftoken)
     498                 :            : {
     499                 :            :         soring_release(r, objs, NULL, stage, n, ftoken);
     500                 :          4 : }
     501                 :            : 
     502                 :            : 
     503                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_releasx, 25.03)
     504                 :            : void
     505         [ -  + ]:      10001 : rte_soring_releasx(struct rte_soring *r, const void *objs,
     506                 :            :         const void *meta, uint32_t stage, uint32_t n, uint32_t ftoken)
     507                 :            : {
     508                 :            :         soring_release(r, objs, meta, stage, n, ftoken);
     509                 :      10001 : }
     510                 :            : 
     511                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_enqueue_bulk, 25.03)
     512                 :            : uint32_t
     513   [ +  -  -  - ]:          1 : rte_soring_enqueue_bulk(struct rte_soring *r, const void *objs, uint32_t n,
     514                 :            :         uint32_t *free_space)
     515                 :            : {
     516                 :          1 :         return soring_enqueue(r, objs, NULL, n, RTE_RING_QUEUE_FIXED,
     517                 :            :                         free_space);
     518                 :            : }
     519                 :            : 
     520                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_enqueux_bulk, 25.03)
     521                 :            : uint32_t
     522   [ #  #  #  # ]:          0 : rte_soring_enqueux_bulk(struct rte_soring *r, const void *objs,
     523                 :            :         const void *meta, uint32_t n, uint32_t *free_space)
     524                 :            : {
     525                 :          0 :         return soring_enqueue(r, objs, meta, n, RTE_RING_QUEUE_FIXED,
     526                 :            :                         free_space);
     527                 :            : }
     528                 :            : 
     529                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_enqueue_burst, 25.03)
     530                 :            : uint32_t
     531   [ +  -  -  - ]:          3 : rte_soring_enqueue_burst(struct rte_soring *r, const void *objs, uint32_t n,
     532                 :            :         uint32_t *free_space)
     533                 :            : {
     534                 :          3 :         return soring_enqueue(r, objs, NULL, n, RTE_RING_QUEUE_VARIABLE,
     535                 :            :                         free_space);
     536                 :            : }
     537                 :            : 
     538                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_enqueux_burst, 25.03)
     539                 :            : uint32_t
     540   [ +  -  -  - ]:          2 : rte_soring_enqueux_burst(struct rte_soring *r, const void *objs,
     541                 :            :         const void *meta, uint32_t n, uint32_t *free_space)
     542                 :            : {
     543                 :          2 :         return soring_enqueue(r, objs, meta, n, RTE_RING_QUEUE_VARIABLE,
     544                 :            :                         free_space);
     545                 :            : }
     546                 :            : 
     547                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_dequeue_bulk, 25.03)
     548                 :            : uint32_t
     549   [ +  -  -  - ]:      10002 : rte_soring_dequeue_bulk(struct rte_soring *r, void *objs, uint32_t num,
     550                 :            :         uint32_t *available)
     551                 :            : {
     552                 :      10002 :         return soring_dequeue(r, objs, NULL, num, RTE_RING_QUEUE_FIXED,
     553                 :            :                         available);
     554                 :            : }
     555                 :            : 
     556                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_dequeux_bulk, 25.03)
     557                 :            : uint32_t
     558   [ +  -  -  - ]:          1 : rte_soring_dequeux_bulk(struct rte_soring *r, void *objs, void *meta,
     559                 :            :         uint32_t num, uint32_t *available)
     560                 :            : {
     561                 :          1 :         return soring_dequeue(r, objs, meta, num, RTE_RING_QUEUE_FIXED,
     562                 :            :                         available);
     563                 :            : }
     564                 :            : 
     565                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_dequeue_burst, 25.03)
     566                 :            : uint32_t
     567   [ +  -  -  - ]:          4 : rte_soring_dequeue_burst(struct rte_soring *r, void *objs, uint32_t num,
     568                 :            :         uint32_t *available)
     569                 :            : {
     570                 :          4 :         return soring_dequeue(r, objs, NULL, num, RTE_RING_QUEUE_VARIABLE,
     571                 :            :                         available);
     572                 :            : }
     573                 :            : 
     574                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_dequeux_burst, 25.03)
     575                 :            : uint32_t
     576   [ +  -  -  - ]:          1 : rte_soring_dequeux_burst(struct rte_soring *r, void *objs, void *meta,
     577                 :            :         uint32_t num, uint32_t *available)
     578                 :            : {
     579                 :          1 :         return soring_dequeue(r, objs, meta, num, RTE_RING_QUEUE_VARIABLE,
     580                 :            :                         available);
     581                 :            : }
     582                 :            : 
     583                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_acquire_bulk, 25.03)
     584                 :            : uint32_t
     585         [ +  - ]:          2 : rte_soring_acquire_bulk(struct rte_soring *r, void *objs,
     586                 :            :         uint32_t stage, uint32_t num, uint32_t *ftoken, uint32_t *available)
     587                 :            : {
     588                 :          2 :         return soring_acquire(r, objs, NULL, stage, num,
     589                 :            :                         RTE_RING_QUEUE_FIXED, ftoken, available);
     590                 :            : }
     591                 :            : 
     592                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_acquirx_bulk, 25.03)
     593                 :            : uint32_t
     594         [ +  + ]:      10000 : rte_soring_acquirx_bulk(struct rte_soring *r, void *objs, void *meta,
     595                 :            :         uint32_t stage, uint32_t num, uint32_t *ftoken, uint32_t *available)
     596                 :            : {
     597                 :      10000 :         return soring_acquire(r, objs, meta, stage, num,
     598                 :            :                         RTE_RING_QUEUE_FIXED, ftoken, available);
     599                 :            : }
     600                 :            : 
     601                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_acquire_burst, 25.03)
     602                 :            : uint32_t
     603         [ #  # ]:          0 : rte_soring_acquire_burst(struct rte_soring *r, void *objs,
     604                 :            :         uint32_t stage, uint32_t num, uint32_t *ftoken, uint32_t *available)
     605                 :            : {
     606                 :          0 :         return soring_acquire(r, objs, NULL, stage, num,
     607                 :            :                         RTE_RING_QUEUE_VARIABLE, ftoken, available);
     608                 :            : }
     609                 :            : 
     610                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_acquirx_burst, 25.03)
     611                 :            : uint32_t
     612         [ +  + ]:          3 : rte_soring_acquirx_burst(struct rte_soring *r, void *objs, void *meta,
     613                 :            :         uint32_t stage, uint32_t num, uint32_t *ftoken, uint32_t *available)
     614                 :            : {
     615                 :          3 :         return soring_acquire(r, objs, meta, stage, num,
     616                 :            :                         RTE_RING_QUEUE_VARIABLE, ftoken, available);
     617                 :            : }
     618                 :            : 
     619                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_count, 25.03)
     620                 :            : unsigned int
     621                 :          4 : rte_soring_count(const struct rte_soring *r)
     622                 :            : {
     623                 :          4 :         uint32_t prod_tail = r->prod.ht.tail;
     624                 :          4 :         uint32_t cons_tail = r->cons.ht.tail;
     625                 :          4 :         uint32_t count = (prod_tail - cons_tail) & r->mask;
     626                 :          4 :         return (count > r->capacity) ? r->capacity : count;
     627                 :            : }
     628                 :            : 
     629                 :            : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_soring_free_count, 25.03)
     630                 :            : unsigned int
     631                 :          2 : rte_soring_free_count(const struct rte_soring *r)
     632                 :            : {
     633                 :          2 :         return r->capacity - rte_soring_count(r);
     634                 :            : }

Generated by: LCOV version 1.14