LCOV - code coverage report
Current view: top level - lib/eal/include/generic - rte_spinlock.h (source / functions) Hit Total Coverage
Test: Code coverage Lines: 18 20 90.0 %
Date: 2024-02-14 00:53:57 Functions: 2 2 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 20 28 71.4 %

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

Generated by: LCOV version 1.14