New upstream version 18.02
[deb_dpdk.git] / lib / librte_eal / common / include / generic / rte_spinlock.h
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
21 #include <rte_lcore.h>
22 #ifdef RTE_FORCE_INTRINSICS
23 #include <rte_common.h>
24 #endif
25 #include <rte_pause.h>
26
27 /**
28  * The rte_spinlock_t type.
29  */
30 typedef struct {
31         volatile int locked; /**< lock status 0 = unlocked, 1 = locked */
32 } rte_spinlock_t;
33
34 /**
35  * A static spinlock initializer.
36  */
37 #define RTE_SPINLOCK_INITIALIZER { 0 }
38
39 /**
40  * Initialize the spinlock to an unlocked state.
41  *
42  * @param sl
43  *   A pointer to the spinlock.
44  */
45 static inline void
46 rte_spinlock_init(rte_spinlock_t *sl)
47 {
48         sl->locked = 0;
49 }
50
51 /**
52  * Take the spinlock.
53  *
54  * @param sl
55  *   A pointer to the spinlock.
56  */
57 static inline void
58 rte_spinlock_lock(rte_spinlock_t *sl);
59
60 #ifdef RTE_FORCE_INTRINSICS
61 static inline void
62 rte_spinlock_lock(rte_spinlock_t *sl)
63 {
64         while (__sync_lock_test_and_set(&sl->locked, 1))
65                 while(sl->locked)
66                         rte_pause();
67 }
68 #endif
69
70 /**
71  * Release the spinlock.
72  *
73  * @param sl
74  *   A pointer to the spinlock.
75  */
76 static inline void
77 rte_spinlock_unlock (rte_spinlock_t *sl);
78
79 #ifdef RTE_FORCE_INTRINSICS
80 static inline void
81 rte_spinlock_unlock (rte_spinlock_t *sl)
82 {
83         __sync_lock_release(&sl->locked);
84 }
85 #endif
86
87 /**
88  * Try to take the lock.
89  *
90  * @param sl
91  *   A pointer to the spinlock.
92  * @return
93  *   1 if the lock is successfully taken; 0 otherwise.
94  */
95 static inline int
96 rte_spinlock_trylock (rte_spinlock_t *sl);
97
98 #ifdef RTE_FORCE_INTRINSICS
99 static inline int
100 rte_spinlock_trylock (rte_spinlock_t *sl)
101 {
102         return __sync_lock_test_and_set(&sl->locked,1) == 0;
103 }
104 #endif
105
106 /**
107  * Test if the lock is taken.
108  *
109  * @param sl
110  *   A pointer to the spinlock.
111  * @return
112  *   1 if the lock is currently taken; 0 otherwise.
113  */
114 static inline int rte_spinlock_is_locked (rte_spinlock_t *sl)
115 {
116         return sl->locked;
117 }
118
119 /**
120  * Test if hardware transactional memory (lock elision) is supported
121  *
122  * @return
123  *   1 if the hardware transactional memory is supported; 0 otherwise.
124  */
125 static inline int rte_tm_supported(void);
126
127 /**
128  * Try to execute critical section in a hardware memory transaction,
129  * if it fails or not available take the spinlock.
130  *
131  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
132  * transaction always aborts the transaction since the CPU is not able to
133  * roll-back should the transaction fail. Therefore, hardware transactional
134  * locks are not advised to be used around rte_eth_rx_burst() and
135  * rte_eth_tx_burst() calls.
136  *
137  * @param sl
138  *   A pointer to the spinlock.
139  */
140 static inline void
141 rte_spinlock_lock_tm(rte_spinlock_t *sl);
142
143 /**
144  * Commit hardware memory transaction or release the spinlock if
145  * the spinlock is used as a fall-back
146  *
147  * @param sl
148  *   A pointer to the spinlock.
149  */
150 static inline void
151 rte_spinlock_unlock_tm(rte_spinlock_t *sl);
152
153 /**
154  * Try to execute critical section in a hardware memory transaction,
155  * if it fails or not available try to take the lock.
156  *
157  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
158  * transaction always aborts the transaction since the CPU is not able to
159  * roll-back should the transaction fail. Therefore, hardware transactional
160  * locks are not advised to be used around rte_eth_rx_burst() and
161  * rte_eth_tx_burst() calls.
162  *
163  * @param sl
164  *   A pointer to the spinlock.
165  * @return
166  *   1 if the hardware memory transaction is successfully started
167  *   or lock is successfully taken; 0 otherwise.
168  */
169 static inline int
170 rte_spinlock_trylock_tm(rte_spinlock_t *sl);
171
172 /**
173  * The rte_spinlock_recursive_t type.
174  */
175 typedef struct {
176         rte_spinlock_t sl; /**< the actual spinlock */
177         volatile int user; /**< core id using lock, -1 for unused */
178         volatile int count; /**< count of time this lock has been called */
179 } rte_spinlock_recursive_t;
180
181 /**
182  * A static recursive spinlock initializer.
183  */
184 #define RTE_SPINLOCK_RECURSIVE_INITIALIZER {RTE_SPINLOCK_INITIALIZER, -1, 0}
185
186 /**
187  * Initialize the recursive spinlock to an unlocked state.
188  *
189  * @param slr
190  *   A pointer to the recursive spinlock.
191  */
192 static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr)
193 {
194         rte_spinlock_init(&slr->sl);
195         slr->user = -1;
196         slr->count = 0;
197 }
198
199 /**
200  * Take the recursive spinlock.
201  *
202  * @param slr
203  *   A pointer to the recursive spinlock.
204  */
205 static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
206 {
207         int id = rte_gettid();
208
209         if (slr->user != id) {
210                 rte_spinlock_lock(&slr->sl);
211                 slr->user = id;
212         }
213         slr->count++;
214 }
215 /**
216  * Release the recursive spinlock.
217  *
218  * @param slr
219  *   A pointer to the recursive spinlock.
220  */
221 static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
222 {
223         if (--(slr->count) == 0) {
224                 slr->user = -1;
225                 rte_spinlock_unlock(&slr->sl);
226         }
227
228 }
229
230 /**
231  * Try to take the recursive lock.
232  *
233  * @param slr
234  *   A pointer to the recursive spinlock.
235  * @return
236  *   1 if the lock is successfully taken; 0 otherwise.
237  */
238 static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
239 {
240         int id = rte_gettid();
241
242         if (slr->user != id) {
243                 if (rte_spinlock_trylock(&slr->sl) == 0)
244                         return 0;
245                 slr->user = id;
246         }
247         slr->count++;
248         return 1;
249 }
250
251
252 /**
253  * Try to execute critical section in a hardware memory transaction,
254  * if it fails or not available take the recursive spinlocks
255  *
256  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
257  * transaction always aborts the transaction since the CPU is not able to
258  * roll-back should the transaction fail. Therefore, hardware transactional
259  * locks are not advised to be used around rte_eth_rx_burst() and
260  * rte_eth_tx_burst() calls.
261  *
262  * @param slr
263  *   A pointer to the recursive spinlock.
264  */
265 static inline void rte_spinlock_recursive_lock_tm(
266         rte_spinlock_recursive_t *slr);
267
268 /**
269  * Commit hardware memory transaction or release the recursive spinlock
270  * if the recursive spinlock is used as a fall-back
271  *
272  * @param slr
273  *   A pointer to the recursive spinlock.
274  */
275 static inline void rte_spinlock_recursive_unlock_tm(
276         rte_spinlock_recursive_t *slr);
277
278 /**
279  * Try to execute critical section in a hardware memory transaction,
280  * if it fails or not available try to take the recursive lock
281  *
282  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
283  * transaction always aborts the transaction since the CPU is not able to
284  * roll-back should the transaction fail. Therefore, hardware transactional
285  * locks are not advised to be used around rte_eth_rx_burst() and
286  * rte_eth_tx_burst() calls.
287  *
288  * @param slr
289  *   A pointer to the recursive spinlock.
290  * @return
291  *   1 if the hardware memory transaction is successfully started
292  *   or lock is successfully taken; 0 otherwise.
293  */
294 static inline int rte_spinlock_recursive_trylock_tm(
295         rte_spinlock_recursive_t *slr);
296
297 #endif /* _RTE_SPINLOCK_H_ */