LCOV - code coverage report
Current view: top level - lib/eal/include/generic - rte_spinlock.h (source / functions) Hit Total Coverage
Test: Code coverage Lines: 21 22 95.5 %
Date: 2026-06-01 18:36:17 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 11 18 61.1 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2014 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #ifndef _RTE_SPINLOCK_H_
       6                 :            : #define _RTE_SPINLOCK_H_
       7                 :            : 
       8                 :            : /**
       9                 :            :  * @file
      10                 :            :  * DPDK spinlocks
      11                 :            :  *
      12                 :            :  * This is an API for spinlocks.
      13                 :            :  * This kind of lock simply waits in a loop
      14                 :            :  * repeatedly checking until the lock becomes available.
      15                 :            :  *
      16                 :            :  * Some functions may have an architecture-specific implementation
      17                 :            :  * if RTE_FORCE_INTRINSICS is disabled.
      18                 :            :  * The hardware transactional memory (lock elision) functions have _tm suffix
      19                 :            :  * and are implemented in architecture-specific files.
      20                 :            :  *
      21                 :            :  * All locks must be initialised before use, and only initialised once.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <rte_lcore.h>
      25                 :            : #ifdef RTE_FORCE_INTRINSICS
      26                 :            : #include <rte_common.h>
      27                 :            : #endif
      28                 :            : #include <rte_debug.h>
      29                 :            : #include <rte_lock_annotations.h>
      30                 :            : #include <rte_pause.h>
      31                 :            : #include <rte_stdatomic.h>
      32                 :            : 
      33                 :            : #ifdef __cplusplus
      34                 :            : extern "C" {
      35                 :            : #endif
      36                 :            : 
      37                 :            : /**
      38                 :            :  * The rte_spinlock_t type.
      39                 :            :  */
      40                 :            : typedef struct __rte_capability("spinlock") {
      41                 :            :         volatile RTE_ATOMIC(int) locked; /**< lock status 0 = unlocked, 1 = locked */
      42                 :            : } rte_spinlock_t;
      43                 :            : 
      44                 :            : /**
      45                 :            :  * A static spinlock initializer.
      46                 :            :  */
      47                 :            : #define RTE_SPINLOCK_INITIALIZER { 0 }
      48                 :            : 
      49                 :            : /**
      50                 :            :  * Initialize the spinlock to an unlocked state.
      51                 :            :  *
      52                 :            :  * @param sl
      53                 :            :  *   A pointer to the spinlock.
      54                 :            :  */
      55                 :            : static inline void
      56                 :            : rte_spinlock_init(rte_spinlock_t *sl)
      57                 :            : {
      58   [ #  #  #  # ]:    1499749 :         sl->locked = 0;
      59                 :          0 : }
      60                 :            : 
      61                 :            : /**
      62                 :            :  * Take the spinlock.
      63                 :            :  *
      64                 :            :  * @param sl
      65                 :            :  *   A pointer to the spinlock.
      66                 :            :  */
      67                 :            : static inline void
      68                 :            : rte_spinlock_lock(rte_spinlock_t *sl)
      69                 :            :         __rte_acquire_capability(sl);
      70                 :            : 
      71                 :            : #ifdef RTE_FORCE_INTRINSICS
      72                 :            : static inline void
      73                 :            : rte_spinlock_lock(rte_spinlock_t *sl)
      74                 :            :         __rte_no_thread_safety_analysis
      75                 :            : {
      76                 :            :         int exp = 0;
      77                 :            : 
      78                 :            :         while (!rte_atomic_compare_exchange_strong_explicit(&sl->locked, &exp, 1,
      79                 :            :                                 rte_memory_order_acquire, rte_memory_order_relaxed)) {
      80                 :            :                 rte_wait_until_equal_32((volatile uint32_t *)(uintptr_t)&sl->locked,
      81                 :            :                                0, rte_memory_order_relaxed);
      82                 :            :                 exp = 0;
      83                 :            :         }
      84                 :            : }
      85                 :            : #endif
      86                 :            : 
      87                 :            : /**
      88                 :            :  * Release the spinlock.
      89                 :            :  *
      90                 :            :  * @param sl
      91                 :            :  *   A pointer to the spinlock.
      92                 :            :  */
      93                 :            : static inline void
      94                 :            : rte_spinlock_unlock(rte_spinlock_t *sl)
      95                 :            :         __rte_release_capability(sl);
      96                 :            : 
      97                 :            : #ifdef RTE_FORCE_INTRINSICS
      98                 :            : static inline void
      99                 :            : rte_spinlock_unlock(rte_spinlock_t *sl)
     100                 :            :         __rte_no_thread_safety_analysis
     101                 :            : {
     102                 :            :         rte_atomic_store_explicit(&sl->locked, 0, rte_memory_order_release);
     103                 :            : }
     104                 :            : #endif
     105                 :            : 
     106                 :            : /**
     107                 :            :  * Try to take the lock.
     108                 :            :  *
     109                 :            :  * @param sl
     110                 :            :  *   A pointer to the spinlock.
     111                 :            :  * @return
     112                 :            :  *   1 if the lock is successfully taken; 0 otherwise.
     113                 :            :  */
     114                 :            : __rte_warn_unused_result
     115                 :            : static inline int
     116                 :            : rte_spinlock_trylock(rte_spinlock_t *sl)
     117                 :            :         __rte_try_acquire_capability(true, sl);
     118                 :            : 
     119                 :            : #ifdef RTE_FORCE_INTRINSICS
     120                 :            : static inline int
     121                 :            : rte_spinlock_trylock(rte_spinlock_t *sl)
     122                 :            :         __rte_no_thread_safety_analysis
     123                 :            : {
     124                 :            :         int exp = 0;
     125                 :            :         return rte_atomic_compare_exchange_strong_explicit(&sl->locked, &exp, 1,
     126                 :            :                                 rte_memory_order_acquire, rte_memory_order_relaxed);
     127                 :            : }
     128                 :            : #endif
     129                 :            : 
     130                 :            : /**
     131                 :            :  * Test if the lock is taken.
     132                 :            :  *
     133                 :            :  * @param sl
     134                 :            :  *   A pointer to the spinlock.
     135                 :            :  * @return
     136                 :            :  *   1 if the lock is currently taken; 0 otherwise.
     137                 :            :  */
     138                 :            : static inline int rte_spinlock_is_locked (rte_spinlock_t *sl)
     139                 :            : {
     140         [ -  + ]:          1 :         return rte_atomic_load_explicit(&sl->locked, rte_memory_order_acquire);
     141                 :            : }
     142                 :            : 
     143                 :            : /**
     144                 :            :  * Test if hardware transactional memory (lock elision) is supported
     145                 :            :  *
     146                 :            :  * @return
     147                 :            :  *   1 if the hardware transactional memory is supported; 0 otherwise.
     148                 :            :  */
     149                 :            : static inline int rte_tm_supported(void);
     150                 :            : 
     151                 :            : /**
     152                 :            :  * Try to execute critical section in a hardware memory transaction,
     153                 :            :  * if it fails or not available take the spinlock.
     154                 :            :  *
     155                 :            :  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
     156                 :            :  * transaction always aborts the transaction since the CPU is not able to
     157                 :            :  * roll-back should the transaction fail. Therefore, hardware transactional
     158                 :            :  * locks are not advised to be used around rte_eth_rx_burst() and
     159                 :            :  * rte_eth_tx_burst() calls.
     160                 :            :  *
     161                 :            :  * @param sl
     162                 :            :  *   A pointer to the spinlock.
     163                 :            :  */
     164                 :            : static inline void
     165                 :            : rte_spinlock_lock_tm(rte_spinlock_t *sl)
     166                 :            :         __rte_acquire_capability(sl);
     167                 :            : 
     168                 :            : /**
     169                 :            :  * Commit hardware memory transaction or release the spinlock if
     170                 :            :  * the spinlock is used as a fall-back
     171                 :            :  *
     172                 :            :  * @param sl
     173                 :            :  *   A pointer to the spinlock.
     174                 :            :  */
     175                 :            : static inline void
     176                 :            : rte_spinlock_unlock_tm(rte_spinlock_t *sl)
     177                 :            :         __rte_release_capability(sl);
     178                 :            : 
     179                 :            : /**
     180                 :            :  * Try to execute critical section in a hardware memory transaction,
     181                 :            :  * if it fails or not available try to take the lock.
     182                 :            :  *
     183                 :            :  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
     184                 :            :  * transaction always aborts the transaction since the CPU is not able to
     185                 :            :  * roll-back should the transaction fail. Therefore, hardware transactional
     186                 :            :  * locks are not advised to be used around rte_eth_rx_burst() and
     187                 :            :  * rte_eth_tx_burst() calls.
     188                 :            :  *
     189                 :            :  * @param sl
     190                 :            :  *   A pointer to the spinlock.
     191                 :            :  * @return
     192                 :            :  *   1 if the hardware memory transaction is successfully started
     193                 :            :  *   or lock is successfully taken; 0 otherwise.
     194                 :            :  */
     195                 :            : __rte_warn_unused_result
     196                 :            : static inline int
     197                 :            : rte_spinlock_trylock_tm(rte_spinlock_t *sl)
     198                 :            :         __rte_try_acquire_capability(true, sl);
     199                 :            : 
     200                 :            : /**
     201                 :            :  * The rte_spinlock_recursive_t type.
     202                 :            :  */
     203                 :            : typedef struct {
     204                 :            :         rte_spinlock_t sl; /**< the actual spinlock */
     205                 :            :         RTE_ATOMIC(int) owner; /**< thread id owning lock, -1 for unused */
     206                 :            :         int count; /**< count of time this lock has been called */
     207                 :            : } rte_spinlock_recursive_t;
     208                 :            : 
     209                 :            : /**
     210                 :            :  * A static recursive spinlock initializer.
     211                 :            :  */
     212                 :            : #define RTE_SPINLOCK_RECURSIVE_INITIALIZER {RTE_SPINLOCK_INITIALIZER, -1, 0}
     213                 :            : 
     214                 :            : /**
     215                 :            :  * Initialize the recursive spinlock to an unlocked state.
     216                 :            :  *
     217                 :            :  * @param slr
     218                 :            :  *   A pointer to the recursive spinlock.
     219                 :            :  */
     220                 :            : static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr)
     221                 :            : {
     222                 :            :         rte_spinlock_init(&slr->sl);
     223                 :          1 :         rte_atomic_store_explicit(&slr->owner, -1, rte_memory_order_relaxed);
     224                 :          1 :         slr->count = 0;
     225                 :            : }
     226                 :            : 
     227                 :            : /**
     228                 :            :  * Take the recursive spinlock.
     229                 :            :  *
     230                 :            :  * @param slr
     231                 :            :  *   A pointer to the recursive spinlock.
     232                 :            :  */
     233         [ +  + ]:        171 : static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
     234                 :            :         __rte_no_thread_safety_analysis
     235                 :            : {
     236                 :            :         int id = rte_gettid();
     237                 :            : 
     238         [ +  + ]:        171 :         if (rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) != id) {
     239                 :        169 :                 rte_spinlock_lock(&slr->sl);
     240                 :        169 :                 rte_atomic_store_explicit(&slr->owner, id, rte_memory_order_relaxed);
     241                 :            :         }
     242                 :        171 :         slr->count++;
     243                 :        171 : }
     244                 :            : /**
     245                 :            :  * Release the recursive spinlock.
     246                 :            :  *
     247                 :            :  * @param slr
     248                 :            :  *   A pointer to the recursive spinlock.
     249                 :            :  */
     250                 :        174 : static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
     251                 :            :         __rte_no_thread_safety_analysis
     252                 :            : {
     253                 :            :         RTE_ASSERT(rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) == rte_gettid());
     254                 :            :         RTE_ASSERT(slr->count > 0);
     255         [ +  + ]:        174 :         if (--(slr->count) == 0) {
     256                 :        170 :                 rte_atomic_store_explicit(&slr->owner, -1, rte_memory_order_relaxed);
     257                 :        170 :                 rte_spinlock_unlock(&slr->sl);
     258                 :            :         }
     259                 :        174 : }
     260                 :            : 
     261                 :            : /**
     262                 :            :  * Try to take the recursive lock.
     263                 :            :  *
     264                 :            :  * @param slr
     265                 :            :  *   A pointer to the recursive spinlock.
     266                 :            :  * @return
     267                 :            :  *   1 if the lock is successfully taken; 0 otherwise.
     268                 :            :  */
     269                 :            : __rte_warn_unused_result
     270         [ -  + ]:          3 : static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
     271                 :            :         __rte_no_thread_safety_analysis
     272                 :            : {
     273                 :            :         int id = rte_gettid();
     274                 :            : 
     275         [ +  + ]:          3 :         if (rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) != id) {
     276         [ +  - ]:          1 :                 if (rte_spinlock_trylock(&slr->sl) == 0)
     277                 :            :                         return 0;
     278                 :          1 :                 rte_atomic_store_explicit(&slr->owner, id, rte_memory_order_relaxed);
     279                 :            :         }
     280                 :          3 :         slr->count++;
     281                 :          3 :         return 1;
     282                 :            : }
     283                 :            : 
     284                 :            : 
     285                 :            : /**
     286                 :            :  * Try to execute critical section in a hardware memory transaction,
     287                 :            :  * if it fails or not available take the recursive spinlocks
     288                 :            :  *
     289                 :            :  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
     290                 :            :  * transaction always aborts the transaction since the CPU is not able to
     291                 :            :  * roll-back should the transaction fail. Therefore, hardware transactional
     292                 :            :  * locks are not advised to be used around rte_eth_rx_burst() and
     293                 :            :  * rte_eth_tx_burst() calls.
     294                 :            :  *
     295                 :            :  * @param slr
     296                 :            :  *   A pointer to the recursive spinlock.
     297                 :            :  */
     298                 :            : static inline void rte_spinlock_recursive_lock_tm(
     299                 :            :         rte_spinlock_recursive_t *slr);
     300                 :            : 
     301                 :            : /**
     302                 :            :  * Commit hardware memory transaction or release the recursive spinlock
     303                 :            :  * if the recursive spinlock is used as a fall-back
     304                 :            :  *
     305                 :            :  * @param slr
     306                 :            :  *   A pointer to the recursive spinlock.
     307                 :            :  */
     308                 :            : static inline void rte_spinlock_recursive_unlock_tm(
     309                 :            :         rte_spinlock_recursive_t *slr);
     310                 :            : 
     311                 :            : /**
     312                 :            :  * Try to execute critical section in a hardware memory transaction,
     313                 :            :  * if it fails or not available try to take the recursive lock
     314                 :            :  *
     315                 :            :  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
     316                 :            :  * transaction always aborts the transaction since the CPU is not able to
     317                 :            :  * roll-back should the transaction fail. Therefore, hardware transactional
     318                 :            :  * locks are not advised to be used around rte_eth_rx_burst() and
     319                 :            :  * rte_eth_tx_burst() calls.
     320                 :            :  *
     321                 :            :  * @param slr
     322                 :            :  *   A pointer to the recursive spinlock.
     323                 :            :  * @return
     324                 :            :  *   1 if the hardware memory transaction is successfully started
     325                 :            :  *   or lock is successfully taken; 0 otherwise.
     326                 :            :  */
     327                 :            : __rte_warn_unused_result
     328                 :            : static inline int rte_spinlock_recursive_trylock_tm(
     329                 :            :         rte_spinlock_recursive_t *slr);
     330                 :            : 
     331                 :            : #ifdef __cplusplus
     332                 :            : }
     333                 :            : #endif
     334                 :            : 
     335                 :            : #endif /* _RTE_SPINLOCK_H_ */

Generated by: LCOV version 1.14