lib: remove librte_ prefix from directory names
[dpdk.git] / lib / eal / include / generic / rte_ticketlock.h
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
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24
25 #include <rte_common.h>
26 #include <rte_lcore.h>
27 #include <rte_pause.h>
28
29 /**
30  * The rte_ticketlock_t type.
31  */
32 typedef union {
33         uint32_t tickets;
34         struct {
35                 uint16_t current;
36                 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         __atomic_store_n(&tl->tickets, 0, __ATOMIC_RELAXED);
55 }
56
57 /**
58  * Take the ticketlock.
59  *
60  * @param tl
61  *   A pointer to the ticketlock.
62  */
63 static inline void
64 rte_ticketlock_lock(rte_ticketlock_t *tl)
65 {
66         uint16_t me = __atomic_fetch_add(&tl->s.next, 1, __ATOMIC_RELAXED);
67         rte_wait_until_equal_16(&tl->s.current, me, __ATOMIC_ACQUIRE);
68 }
69
70 /**
71  * Release the ticketlock.
72  *
73  * @param tl
74  *   A pointer to the ticketlock.
75  */
76 static inline void
77 rte_ticketlock_unlock(rte_ticketlock_t *tl)
78 {
79         uint16_t i = __atomic_load_n(&tl->s.current, __ATOMIC_RELAXED);
80         __atomic_store_n(&tl->s.current, i + 1, __ATOMIC_RELEASE);
81 }
82
83 /**
84  * Try to take the lock.
85  *
86  * @param tl
87  *   A pointer to the ticketlock.
88  * @return
89  *   1 if the lock is successfully taken; 0 otherwise.
90  */
91 static inline int
92 rte_ticketlock_trylock(rte_ticketlock_t *tl)
93 {
94         rte_ticketlock_t old, new;
95         old.tickets = __atomic_load_n(&tl->tickets, __ATOMIC_RELAXED);
96         new.tickets = old.tickets;
97         new.s.next++;
98         if (old.s.next == old.s.current) {
99                 if (__atomic_compare_exchange_n(&tl->tickets, &old.tickets,
100                     new.tickets, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
101                         return 1;
102         }
103
104         return 0;
105 }
106
107 /**
108  * Test if the lock is taken.
109  *
110  * @param tl
111  *   A pointer to the ticketlock.
112  * @return
113  *   1 if the lock is currently taken; 0 otherwise.
114  */
115 static inline int
116 rte_ticketlock_is_locked(rte_ticketlock_t *tl)
117 {
118         rte_ticketlock_t tic;
119         tic.tickets = __atomic_load_n(&tl->tickets, __ATOMIC_ACQUIRE);
120         return (tic.s.current != tic.s.next);
121 }
122
123 /**
124  * The rte_ticketlock_recursive_t type.
125  */
126 #define TICKET_LOCK_INVALID_ID -1
127
128 typedef struct {
129         rte_ticketlock_t tl; /**< the actual ticketlock */
130         int user; /**< core id using lock, TICKET_LOCK_INVALID_ID for unused */
131         unsigned int count; /**< count of time this lock has been called */
132 } rte_ticketlock_recursive_t;
133
134 /**
135  * A static recursive ticketlock initializer.
136  */
137 #define RTE_TICKETLOCK_RECURSIVE_INITIALIZER {RTE_TICKETLOCK_INITIALIZER, \
138                                               TICKET_LOCK_INVALID_ID, 0}
139
140 /**
141  * Initialize the recursive ticketlock to an unlocked state.
142  *
143  * @param tlr
144  *   A pointer to the recursive ticketlock.
145  */
146 static inline void
147 rte_ticketlock_recursive_init(rte_ticketlock_recursive_t *tlr)
148 {
149         rte_ticketlock_init(&tlr->tl);
150         __atomic_store_n(&tlr->user, TICKET_LOCK_INVALID_ID, __ATOMIC_RELAXED);
151         tlr->count = 0;
152 }
153
154 /**
155  * Take the recursive ticketlock.
156  *
157  * @param tlr
158  *   A pointer to the recursive ticketlock.
159  */
160 static inline void
161 rte_ticketlock_recursive_lock(rte_ticketlock_recursive_t *tlr)
162 {
163         int id = rte_gettid();
164
165         if (__atomic_load_n(&tlr->user, __ATOMIC_RELAXED) != id) {
166                 rte_ticketlock_lock(&tlr->tl);
167                 __atomic_store_n(&tlr->user, id, __ATOMIC_RELAXED);
168         }
169         tlr->count++;
170 }
171
172 /**
173  * Release the recursive ticketlock.
174  *
175  * @param tlr
176  *   A pointer to the recursive ticketlock.
177  */
178 static inline void
179 rte_ticketlock_recursive_unlock(rte_ticketlock_recursive_t *tlr)
180 {
181         if (--(tlr->count) == 0) {
182                 __atomic_store_n(&tlr->user, TICKET_LOCK_INVALID_ID,
183                                  __ATOMIC_RELAXED);
184                 rte_ticketlock_unlock(&tlr->tl);
185         }
186 }
187
188 /**
189  * Try to take the recursive lock.
190  *
191  * @param tlr
192  *   A pointer to the recursive ticketlock.
193  * @return
194  *   1 if the lock is successfully taken; 0 otherwise.
195  */
196 static inline int
197 rte_ticketlock_recursive_trylock(rte_ticketlock_recursive_t *tlr)
198 {
199         int id = rte_gettid();
200
201         if (__atomic_load_n(&tlr->user, __ATOMIC_RELAXED) != id) {
202                 if (rte_ticketlock_trylock(&tlr->tl) == 0)
203                         return 0;
204                 __atomic_store_n(&tlr->user, id, __ATOMIC_RELAXED);
205         }
206         tlr->count++;
207         return 1;
208 }
209
210 #ifdef __cplusplus
211 }
212 #endif
213
214 #endif /* _RTE_TICKETLOCK_H_ */