New upstream version 17.08
[deb_dpdk.git] / lib / librte_eal / common / include / generic / rte_spinlock.h
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #ifndef _RTE_SPINLOCK_H_
35 #define _RTE_SPINLOCK_H_
36
37 /**
38  * @file
39  *
40  * RTE Spinlocks
41  *
42  * This file defines an API for read-write locks, which are implemented
43  * in an architecture-specific way. This kind of lock simply waits in
44  * a loop repeatedly checking until the lock becomes available.
45  *
46  * All locks must be initialised before use, and only initialised once.
47  *
48  */
49
50 #include <rte_lcore.h>
51 #ifdef RTE_FORCE_INTRINSICS
52 #include <rte_common.h>
53 #endif
54 #include <rte_pause.h>
55
56 /**
57  * The rte_spinlock_t type.
58  */
59 typedef struct {
60         volatile int locked; /**< lock status 0 = unlocked, 1 = locked */
61 } rte_spinlock_t;
62
63 /**
64  * A static spinlock initializer.
65  */
66 #define RTE_SPINLOCK_INITIALIZER { 0 }
67
68 /**
69  * Initialize the spinlock to an unlocked state.
70  *
71  * @param sl
72  *   A pointer to the spinlock.
73  */
74 static inline void
75 rte_spinlock_init(rte_spinlock_t *sl)
76 {
77         sl->locked = 0;
78 }
79
80 /**
81  * Take the spinlock.
82  *
83  * @param sl
84  *   A pointer to the spinlock.
85  */
86 static inline void
87 rte_spinlock_lock(rte_spinlock_t *sl);
88
89 #ifdef RTE_FORCE_INTRINSICS
90 static inline void
91 rte_spinlock_lock(rte_spinlock_t *sl)
92 {
93         while (__sync_lock_test_and_set(&sl->locked, 1))
94                 while(sl->locked)
95                         rte_pause();
96 }
97 #endif
98
99 /**
100  * Release the spinlock.
101  *
102  * @param sl
103  *   A pointer to the spinlock.
104  */
105 static inline void
106 rte_spinlock_unlock (rte_spinlock_t *sl);
107
108 #ifdef RTE_FORCE_INTRINSICS
109 static inline void
110 rte_spinlock_unlock (rte_spinlock_t *sl)
111 {
112         __sync_lock_release(&sl->locked);
113 }
114 #endif
115
116 /**
117  * Try to take the lock.
118  *
119  * @param sl
120  *   A pointer to the spinlock.
121  * @return
122  *   1 if the lock is successfully taken; 0 otherwise.
123  */
124 static inline int
125 rte_spinlock_trylock (rte_spinlock_t *sl);
126
127 #ifdef RTE_FORCE_INTRINSICS
128 static inline int
129 rte_spinlock_trylock (rte_spinlock_t *sl)
130 {
131         return __sync_lock_test_and_set(&sl->locked,1) == 0;
132 }
133 #endif
134
135 /**
136  * Test if the lock is taken.
137  *
138  * @param sl
139  *   A pointer to the spinlock.
140  * @return
141  *   1 if the lock is currently taken; 0 otherwise.
142  */
143 static inline int rte_spinlock_is_locked (rte_spinlock_t *sl)
144 {
145         return sl->locked;
146 }
147
148 /**
149  * Test if hardware transactional memory (lock elision) is supported
150  *
151  * @return
152  *   1 if the hardware transactional memory is supported; 0 otherwise.
153  */
154 static inline int rte_tm_supported(void);
155
156 /**
157  * Try to execute critical section in a hardware memory transaction,
158  * if it fails or not available take the spinlock.
159  *
160  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
161  * transaction always aborts the transaction since the CPU is not able to
162  * roll-back should the transaction fail. Therefore, hardware transactional
163  * locks are not advised to be used around rte_eth_rx_burst() and
164  * rte_eth_tx_burst() calls.
165  *
166  * @param sl
167  *   A pointer to the spinlock.
168  */
169 static inline void
170 rte_spinlock_lock_tm(rte_spinlock_t *sl);
171
172 /**
173  * Commit hardware memory transaction or release the spinlock if
174  * the spinlock is used as a fall-back
175  *
176  * @param sl
177  *   A pointer to the spinlock.
178  */
179 static inline void
180 rte_spinlock_unlock_tm(rte_spinlock_t *sl);
181
182 /**
183  * Try to execute critical section in a hardware memory transaction,
184  * if it fails or not available try to take the lock.
185  *
186  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
187  * transaction always aborts the transaction since the CPU is not able to
188  * roll-back should the transaction fail. Therefore, hardware transactional
189  * locks are not advised to be used around rte_eth_rx_burst() and
190  * rte_eth_tx_burst() calls.
191  *
192  * @param sl
193  *   A pointer to the spinlock.
194  * @return
195  *   1 if the hardware memory transaction is successfully started
196  *   or lock is successfully taken; 0 otherwise.
197  */
198 static inline int
199 rte_spinlock_trylock_tm(rte_spinlock_t *sl);
200
201 /**
202  * The rte_spinlock_recursive_t type.
203  */
204 typedef struct {
205         rte_spinlock_t sl; /**< the actual spinlock */
206         volatile int user; /**< core id using lock, -1 for unused */
207         volatile int count; /**< count of time this lock has been called */
208 } rte_spinlock_recursive_t;
209
210 /**
211  * A static recursive spinlock initializer.
212  */
213 #define RTE_SPINLOCK_RECURSIVE_INITIALIZER {RTE_SPINLOCK_INITIALIZER, -1, 0}
214
215 /**
216  * Initialize the recursive spinlock to an unlocked state.
217  *
218  * @param slr
219  *   A pointer to the recursive spinlock.
220  */
221 static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr)
222 {
223         rte_spinlock_init(&slr->sl);
224         slr->user = -1;
225         slr->count = 0;
226 }
227
228 /**
229  * Take the recursive spinlock.
230  *
231  * @param slr
232  *   A pointer to the recursive spinlock.
233  */
234 static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
235 {
236         int id = rte_gettid();
237
238         if (slr->user != id) {
239                 rte_spinlock_lock(&slr->sl);
240                 slr->user = id;
241         }
242         slr->count++;
243 }
244 /**
245  * Release the recursive spinlock.
246  *
247  * @param slr
248  *   A pointer to the recursive spinlock.
249  */
250 static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
251 {
252         if (--(slr->count) == 0) {
253                 slr->user = -1;
254                 rte_spinlock_unlock(&slr->sl);
255         }
256
257 }
258
259 /**
260  * Try to take the recursive lock.
261  *
262  * @param slr
263  *   A pointer to the recursive spinlock.
264  * @return
265  *   1 if the lock is successfully taken; 0 otherwise.
266  */
267 static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
268 {
269         int id = rte_gettid();
270
271         if (slr->user != id) {
272                 if (rte_spinlock_trylock(&slr->sl) == 0)
273                         return 0;
274                 slr->user = id;
275         }
276         slr->count++;
277         return 1;
278 }
279
280
281 /**
282  * Try to execute critical section in a hardware memory transaction,
283  * if it fails or not available take the recursive spinlocks
284  *
285  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
286  * transaction always aborts the transaction since the CPU is not able to
287  * roll-back should the transaction fail. Therefore, hardware transactional
288  * locks are not advised to be used around rte_eth_rx_burst() and
289  * rte_eth_tx_burst() calls.
290  *
291  * @param slr
292  *   A pointer to the recursive spinlock.
293  */
294 static inline void rte_spinlock_recursive_lock_tm(
295         rte_spinlock_recursive_t *slr);
296
297 /**
298  * Commit hardware memory transaction or release the recursive spinlock
299  * if the recursive spinlock is used as a fall-back
300  *
301  * @param slr
302  *   A pointer to the recursive spinlock.
303  */
304 static inline void rte_spinlock_recursive_unlock_tm(
305         rte_spinlock_recursive_t *slr);
306
307 /**
308  * Try to execute critical section in a hardware memory transaction,
309  * if it fails or not available try to take the recursive lock
310  *
311  * NOTE: An attempt to perform a HW I/O operation inside a hardware memory
312  * transaction always aborts the transaction since the CPU is not able to
313  * roll-back should the transaction fail. Therefore, hardware transactional
314  * locks are not advised to be used around rte_eth_rx_burst() and
315  * rte_eth_tx_burst() calls.
316  *
317  * @param slr
318  *   A pointer to the recursive spinlock.
319  * @return
320  *   1 if the hardware memory transaction is successfully started
321  *   or lock is successfully taken; 0 otherwise.
322  */
323 static inline int rte_spinlock_recursive_trylock_tm(
324         rte_spinlock_recursive_t *slr);
325
326 #endif /* _RTE_SPINLOCK_H_ */