1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019 Arm Limited
5 #ifndef _RTE_TICKETLOCK_H_
6 #define _RTE_TICKETLOCK_H_
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
17 * All locks must be initialised before use, and only initialised once.
25 #include <rte_common.h>
26 #include <rte_lcore.h>
27 #include <rte_pause.h>
30 * The rte_ticketlock_t type.
41 * A static ticketlock initializer.
43 #define RTE_TICKETLOCK_INITIALIZER { 0 }
46 * Initialize the ticketlock to an unlocked state.
49 * A pointer to the ticketlock.
51 static inline __rte_experimental void
52 rte_ticketlock_init(rte_ticketlock_t *tl)
54 __atomic_store_n(&tl->tickets, 0, __ATOMIC_RELAXED);
58 * Take the ticketlock.
61 * A pointer to the ticketlock.
63 static inline __rte_experimental void
64 rte_ticketlock_lock(rte_ticketlock_t *tl)
66 uint16_t me = __atomic_fetch_add(&tl->s.next, 1, __ATOMIC_RELAXED);
67 while (__atomic_load_n(&tl->s.current, __ATOMIC_ACQUIRE) != me)
72 * Release the ticketlock.
75 * A pointer to the ticketlock.
77 static inline __rte_experimental void
78 rte_ticketlock_unlock(rte_ticketlock_t *tl)
80 uint16_t i = __atomic_load_n(&tl->s.current, __ATOMIC_RELAXED);
81 __atomic_store_n(&tl->s.current, i + 1, __ATOMIC_RELEASE);
85 * Try to take the lock.
88 * A pointer to the ticketlock.
90 * 1 if the lock is successfully taken; 0 otherwise.
92 static inline __rte_experimental int
93 rte_ticketlock_trylock(rte_ticketlock_t *tl)
95 rte_ticketlock_t old, new;
96 old.tickets = __atomic_load_n(&tl->tickets, __ATOMIC_RELAXED);
97 new.tickets = old.tickets;
99 if (old.s.next == old.s.current) {
100 if (__atomic_compare_exchange_n(&tl->tickets, &old.tickets,
101 new.tickets, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
109 * Test if the lock is taken.
112 * A pointer to the ticketlock.
114 * 1 if the lock is currently taken; 0 otherwise.
116 static inline __rte_experimental int
117 rte_ticketlock_is_locked(rte_ticketlock_t *tl)
119 rte_ticketlock_t tic;
120 tic.tickets = __atomic_load_n(&tl->tickets, __ATOMIC_ACQUIRE);
121 return (tic.s.current != tic.s.next);
125 * The rte_ticketlock_recursive_t type.
127 #define TICKET_LOCK_INVALID_ID -1
130 rte_ticketlock_t tl; /**< the actual ticketlock */
131 int user; /**< core id using lock, TICKET_LOCK_INVALID_ID for unused */
132 unsigned int count; /**< count of time this lock has been called */
133 } rte_ticketlock_recursive_t;
136 * A static recursive ticketlock initializer.
138 #define RTE_TICKETLOCK_RECURSIVE_INITIALIZER {RTE_TICKETLOCK_INITIALIZER, \
139 TICKET_LOCK_INVALID_ID, 0}
142 * Initialize the recursive ticketlock to an unlocked state.
145 * A pointer to the recursive ticketlock.
147 static inline __rte_experimental void
148 rte_ticketlock_recursive_init(rte_ticketlock_recursive_t *tlr)
150 rte_ticketlock_init(&tlr->tl);
151 __atomic_store_n(&tlr->user, TICKET_LOCK_INVALID_ID, __ATOMIC_RELAXED);
156 * Take the recursive ticketlock.
159 * A pointer to the recursive ticketlock.
161 static inline __rte_experimental void
162 rte_ticketlock_recursive_lock(rte_ticketlock_recursive_t *tlr)
164 int id = rte_gettid();
166 if (__atomic_load_n(&tlr->user, __ATOMIC_RELAXED) != id) {
167 rte_ticketlock_lock(&tlr->tl);
168 __atomic_store_n(&tlr->user, id, __ATOMIC_RELAXED);
174 * Release the recursive ticketlock.
177 * A pointer to the recursive ticketlock.
179 static inline __rte_experimental void
180 rte_ticketlock_recursive_unlock(rte_ticketlock_recursive_t *tlr)
182 if (--(tlr->count) == 0) {
183 __atomic_store_n(&tlr->user, TICKET_LOCK_INVALID_ID,
185 rte_ticketlock_unlock(&tlr->tl);
190 * Try to take the recursive lock.
193 * A pointer to the recursive ticketlock.
195 * 1 if the lock is successfully taken; 0 otherwise.
197 static inline __rte_experimental int
198 rte_ticketlock_recursive_trylock(rte_ticketlock_recursive_t *tlr)
200 int id = rte_gettid();
202 if (__atomic_load_n(&tlr->user, __ATOMIC_RELAXED) != id) {
203 if (rte_ticketlock_trylock(&tlr->tl) == 0)
205 __atomic_store_n(&tlr->user, id, __ATOMIC_RELAXED);
215 #endif /* _RTE_TICKETLOCK_H_ */