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_ */