Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(c) 2019 Arm Limited 3 : : */ 4 : : 5 : : #ifndef _RTE_TICKETLOCK_H_ 6 : : #define _RTE_TICKETLOCK_H_ 7 : : 8 : : /** 9 : : * @file 10 : : * 11 : : * RTE ticket locks 12 : : * 13 : : * This file defines an API for ticket locks, which give each waiting 14 : : * thread a ticket and take the lock one by one, first come, first 15 : : * serviced. 16 : : * 17 : : * All locks must be initialised before use, and only initialised once. 18 : : */ 19 : : 20 : : #include <rte_common.h> 21 : : #include <rte_lcore.h> 22 : : #include <rte_pause.h> 23 : : #include <rte_stdatomic.h> 24 : : 25 : : #ifdef __cplusplus 26 : : extern "C" { 27 : : #endif 28 : : 29 : : /** 30 : : * The rte_ticketlock_t type. 31 : : */ 32 : : typedef union { 33 : : RTE_ATOMIC(uint32_t) tickets; 34 : : struct { 35 : : RTE_ATOMIC(uint16_t) current; 36 : : RTE_ATOMIC(uint16_t) next; 37 : : } s; 38 : : } rte_ticketlock_t; 39 : : 40 : : /** 41 : : * A static ticketlock initializer. 42 : : */ 43 : : #define RTE_TICKETLOCK_INITIALIZER { 0 } 44 : : 45 : : /** 46 : : * Initialize the ticketlock to an unlocked state. 47 : : * 48 : : * @param tl 49 : : * A pointer to the ticketlock. 50 : : */ 51 : : static inline void 52 : : rte_ticketlock_init(rte_ticketlock_t *tl) 53 : : { 54 : 2 : rte_atomic_store_explicit(&tl->tickets, 0, rte_memory_order_relaxed); 55 : : } 56 : : 57 : : /** 58 : : * Take the ticketlock. 59 : : * 60 : : * @param tl 61 : : * A pointer to the ticketlock. 62 : : */ 63 : : static inline void 64 : 30000 : rte_ticketlock_lock(rte_ticketlock_t *tl) 65 : : { 66 : 30000 : uint16_t me = rte_atomic_fetch_add_explicit(&tl->s.next, 1, rte_memory_order_relaxed); 67 : 30000 : rte_wait_until_equal_16((uint16_t *)(uintptr_t)&tl->s.current, me, 68 : : rte_memory_order_acquire); 69 : 30008 : } 70 : : 71 : : /** 72 : : * Release the ticketlock. 73 : : * 74 : : * @param tl 75 : : * A pointer to the ticketlock. 76 : : */ 77 : : static inline void 78 : 30010 : rte_ticketlock_unlock(rte_ticketlock_t *tl) 79 : : { 80 : 30010 : uint16_t i = rte_atomic_load_explicit(&tl->s.current, rte_memory_order_relaxed); 81 : 30010 : rte_atomic_store_explicit(&tl->s.current, i + 1, rte_memory_order_release); 82 : 30010 : } 83 : : 84 : : /** 85 : : * Try to take the lock. 86 : : * 87 : : * @param tl 88 : : * A pointer to the ticketlock. 89 : : * @return 90 : : * 1 if the lock is successfully taken; 0 otherwise. 91 : : */ 92 : : static inline int 93 : 3 : rte_ticketlock_trylock(rte_ticketlock_t *tl) 94 : : { 95 : : rte_ticketlock_t oldl, newl; 96 : 3 : oldl.tickets = rte_atomic_load_explicit(&tl->tickets, rte_memory_order_relaxed); 97 : 3 : newl.tickets = oldl.tickets; 98 : 3 : newl.s.next++; 99 [ + + ]: 3 : if (oldl.s.next == oldl.s.current) { 100 [ + - ]: 2 : if (rte_atomic_compare_exchange_strong_explicit(&tl->tickets, 101 : : (uint32_t *)(uintptr_t)&oldl.tickets, newl.tickets, 102 : : rte_memory_order_acquire, rte_memory_order_relaxed)) 103 : 2 : return 1; 104 : : } 105 : : 106 : : return 0; 107 : : } 108 : : 109 : : /** 110 : : * Test if the lock is taken. 111 : : * 112 : : * @param tl 113 : : * A pointer to the ticketlock. 114 : : * @return 115 : : * 1 if the lock is currently taken; 0 otherwise. 116 : : */ 117 : : static inline int 118 : : rte_ticketlock_is_locked(rte_ticketlock_t *tl) 119 : : { 120 : : rte_ticketlock_t tic; 121 [ - + ]: 1 : tic.tickets = rte_atomic_load_explicit(&tl->tickets, rte_memory_order_acquire); 122 : : return (tic.s.current != tic.s.next); 123 : : } 124 : : 125 : : /** 126 : : * The rte_ticketlock_recursive_t type. 127 : : */ 128 : : #define TICKET_LOCK_INVALID_ID -1 129 : : 130 : : typedef struct { 131 : : rte_ticketlock_t tl; /**< the actual ticketlock */ 132 : : RTE_ATOMIC(int) user; /**< core id using lock, TICKET_LOCK_INVALID_ID for unused */ 133 : : unsigned int count; /**< count of time this lock has been called */ 134 : : } rte_ticketlock_recursive_t; 135 : : 136 : : /** 137 : : * A static recursive ticketlock initializer. 138 : : */ 139 : : #define RTE_TICKETLOCK_RECURSIVE_INITIALIZER {RTE_TICKETLOCK_INITIALIZER, \ 140 : : TICKET_LOCK_INVALID_ID, 0} 141 : : 142 : : /** 143 : : * Initialize the recursive ticketlock to an unlocked state. 144 : : * 145 : : * @param tlr 146 : : * A pointer to the recursive ticketlock. 147 : : */ 148 : : static inline void 149 : 1 : rte_ticketlock_recursive_init(rte_ticketlock_recursive_t *tlr) 150 : : { 151 : : rte_ticketlock_init(&tlr->tl); 152 : 1 : rte_atomic_store_explicit(&tlr->user, TICKET_LOCK_INVALID_ID, rte_memory_order_relaxed); 153 : 1 : tlr->count = 0; 154 : 1 : } 155 : : 156 : : /** 157 : : * Take the recursive ticketlock. 158 : : * 159 : : * @param tlr 160 : : * A pointer to the recursive ticketlock. 161 : : */ 162 : : static inline void 163 [ - + ]: 4 : rte_ticketlock_recursive_lock(rte_ticketlock_recursive_t *tlr) 164 : : { 165 : : int id = rte_gettid(); 166 : : 167 [ + + ]: 4 : if (rte_atomic_load_explicit(&tlr->user, rte_memory_order_relaxed) != id) { 168 : 2 : rte_ticketlock_lock(&tlr->tl); 169 : 2 : rte_atomic_store_explicit(&tlr->user, id, rte_memory_order_relaxed); 170 : : } 171 : 4 : tlr->count++; 172 : 4 : } 173 : : 174 : : /** 175 : : * Release the recursive ticketlock. 176 : : * 177 : : * @param tlr 178 : : * A pointer to the recursive ticketlock. 179 : : */ 180 : : static inline void 181 : 7 : rte_ticketlock_recursive_unlock(rte_ticketlock_recursive_t *tlr) 182 : : { 183 [ + + ]: 7 : if (--(tlr->count) == 0) { 184 : 3 : rte_atomic_store_explicit(&tlr->user, TICKET_LOCK_INVALID_ID, 185 : : rte_memory_order_relaxed); 186 : 3 : rte_ticketlock_unlock(&tlr->tl); 187 : : } 188 : 7 : } 189 : : 190 : : /** 191 : : * Try to take the recursive lock. 192 : : * 193 : : * @param tlr 194 : : * A pointer to the recursive ticketlock. 195 : : * @return 196 : : * 1 if the lock is successfully taken; 0 otherwise. 197 : : */ 198 : : static inline int 199 [ - + ]: 3 : rte_ticketlock_recursive_trylock(rte_ticketlock_recursive_t *tlr) 200 : : { 201 : : int id = rte_gettid(); 202 : : 203 [ + + ]: 3 : if (rte_atomic_load_explicit(&tlr->user, rte_memory_order_relaxed) != id) { 204 [ + - ]: 1 : if (rte_ticketlock_trylock(&tlr->tl) == 0) 205 : : return 0; 206 : 1 : rte_atomic_store_explicit(&tlr->user, id, rte_memory_order_relaxed); 207 : : } 208 : 3 : tlr->count++; 209 : 3 : return 1; 210 : : } 211 : : 212 : : #ifdef __cplusplus 213 : : } 214 : : #endif 215 : : 216 : : #endif /* _RTE_TICKETLOCK_H_ */