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.
53 rte_ticketlock_init(rte_ticketlock_t
*tl
)
55 __atomic_store_n(&tl
->tickets
, 0, __ATOMIC_RELAXED
);
59 * Take the ticketlock.
62 * A pointer to the ticketlock.
66 rte_ticketlock_lock(rte_ticketlock_t
*tl
)
68 uint16_t me
= __atomic_fetch_add(&tl
->s
.next
, 1, __ATOMIC_RELAXED
);
69 rte_wait_until_equal_16(&tl
->s
.current
, me
, __ATOMIC_ACQUIRE
);
73 * Release the ticketlock.
76 * A pointer to the ticketlock.
80 rte_ticketlock_unlock(rte_ticketlock_t
*tl
)
82 uint16_t i
= __atomic_load_n(&tl
->s
.current
, __ATOMIC_RELAXED
);
83 __atomic_store_n(&tl
->s
.current
, i
+ 1, __ATOMIC_RELEASE
);
87 * Try to take the lock.
90 * A pointer to the ticketlock.
92 * 1 if the lock is successfully taken; 0 otherwise.
96 rte_ticketlock_trylock(rte_ticketlock_t
*tl
)
98 rte_ticketlock_t old
, new;
99 old
.tickets
= __atomic_load_n(&tl
->tickets
, __ATOMIC_RELAXED
);
100 new.tickets
= old
.tickets
;
102 if (old
.s
.next
== old
.s
.current
) {
103 if (__atomic_compare_exchange_n(&tl
->tickets
, &old
.tickets
,
104 new.tickets
, 0, __ATOMIC_ACQUIRE
, __ATOMIC_RELAXED
))
112 * Test if the lock is taken.
115 * A pointer to the ticketlock.
117 * 1 if the lock is currently taken; 0 otherwise.
121 rte_ticketlock_is_locked(rte_ticketlock_t
*tl
)
123 rte_ticketlock_t tic
;
124 tic
.tickets
= __atomic_load_n(&tl
->tickets
, __ATOMIC_ACQUIRE
);
125 return (tic
.s
.current
!= tic
.s
.next
);
129 * The rte_ticketlock_recursive_t type.
131 #define TICKET_LOCK_INVALID_ID -1
134 rte_ticketlock_t tl
; /**< the actual ticketlock */
135 int user
; /**< core id using lock, TICKET_LOCK_INVALID_ID for unused */
136 unsigned int count
; /**< count of time this lock has been called */
137 } rte_ticketlock_recursive_t
;
140 * A static recursive ticketlock initializer.
142 #define RTE_TICKETLOCK_RECURSIVE_INITIALIZER {RTE_TICKETLOCK_INITIALIZER, \
143 TICKET_LOCK_INVALID_ID, 0}
146 * Initialize the recursive ticketlock to an unlocked state.
149 * A pointer to the recursive ticketlock.
153 rte_ticketlock_recursive_init(rte_ticketlock_recursive_t
*tlr
)
155 rte_ticketlock_init(&tlr
->tl
);
156 __atomic_store_n(&tlr
->user
, TICKET_LOCK_INVALID_ID
, __ATOMIC_RELAXED
);
161 * Take the recursive ticketlock.
164 * A pointer to the recursive ticketlock.
168 rte_ticketlock_recursive_lock(rte_ticketlock_recursive_t
*tlr
)
170 int id
= rte_gettid();
172 if (__atomic_load_n(&tlr
->user
, __ATOMIC_RELAXED
) != id
) {
173 rte_ticketlock_lock(&tlr
->tl
);
174 __atomic_store_n(&tlr
->user
, id
, __ATOMIC_RELAXED
);
180 * Release the recursive ticketlock.
183 * A pointer to the recursive ticketlock.
187 rte_ticketlock_recursive_unlock(rte_ticketlock_recursive_t
*tlr
)
189 if (--(tlr
->count
) == 0) {
190 __atomic_store_n(&tlr
->user
, TICKET_LOCK_INVALID_ID
,
192 rte_ticketlock_unlock(&tlr
->tl
);
197 * Try to take the recursive lock.
200 * A pointer to the recursive ticketlock.
202 * 1 if the lock is successfully taken; 0 otherwise.
206 rte_ticketlock_recursive_trylock(rte_ticketlock_recursive_t
*tlr
)
208 int id
= rte_gettid();
210 if (__atomic_load_n(&tlr
->user
, __ATOMIC_RELAXED
) != id
) {
211 if (rte_ticketlock_trylock(&tlr
->tl
) == 0)
213 __atomic_store_n(&tlr
->user
, id
, __ATOMIC_RELAXED
);
223 #endif /* _RTE_TICKETLOCK_H_ */