remove version in all files
[dpdk.git] / lib / librte_eal / common / include / rte_spinlock.h
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2012 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
35 #ifndef _RTE_SPINLOCK_H_
36 #define _RTE_SPINLOCK_H_
37
38 /**
39  * @file
40  *
41  * RTE Spinlocks
42  *
43  * This file defines an API for read-write locks, which are implemented
44  * in an architecture-specific way. This kind of lock simply waits in
45  * a loop repeatedly checking until the lock becomes available.
46  *
47  * All locks must be initialised before use, and only initialised once.
48  *
49  */
50
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54
55 #include <rte_lcore.h>
56
57 /**
58  * The rte_spinlock_t type.
59  */
60 typedef struct {
61         volatile int locked; /**< lock status 0 = unlocked, 1 = locked */
62 } rte_spinlock_t;
63
64 /**
65  * A static spinlock initializer.
66  */
67 #define RTE_SPINLOCK_INITIALIZER { 0 }
68
69 /**
70  * Initialize the spinlock to an unlocked state.
71  *
72  * @param sl
73  *   A pointer to the spinlock.
74  */
75 static inline void
76 rte_spinlock_init(rte_spinlock_t *sl)
77 {
78         sl->locked = 0;
79 }
80
81 /**
82  * Take the spinlock.
83  *
84  * @param sl
85  *   A pointer to the spinlock.
86  */
87 static inline void
88 rte_spinlock_lock(rte_spinlock_t *sl)
89 {
90         int lock_val = 1;
91         asm volatile (
92                         "1:\n"
93                         "xchg %[locked], %[lv]\n"
94                         "test %[lv], %[lv]\n"
95                         "jz 3f\n"
96                         "2:\n"
97                         "pause\n"
98                         "cmp $0, %[locked]\n"
99                         "jnz 2b\n"
100                         "jmp 1b\n"
101                         "3:\n"
102                         : [locked] "=m" (sl->locked), [lv] "=q" (lock_val)
103                         : "[lv]" (lock_val)
104                         : "memory");
105 }
106
107 /**
108  * Release the spinlock.
109  *
110  * @param sl
111  *   A pointer to the spinlock.
112  */
113 static inline void
114 rte_spinlock_unlock (rte_spinlock_t *sl)
115 {
116         int unlock_val = 0;
117         asm volatile (
118                         "xchg %[locked], %[ulv]\n"
119                         : [locked] "=m" (sl->locked), [ulv] "=q" (unlock_val)
120                         : "[ulv]" (unlock_val)
121                         : "memory");
122 }
123
124 /**
125  * Try to take the lock.
126  *
127  * @param sl
128  *   A pointer to the spinlock.
129  * @return
130  *   1 if the lock is successfully taken; 0 otherwise.
131  */
132 static inline int
133 rte_spinlock_trylock (rte_spinlock_t *sl)
134 {
135         int lockval = 1;
136
137         asm volatile (
138                         "xchg %[locked], %[lockval]"
139                         : [locked] "=m" (sl->locked), [lockval] "=q" (lockval)
140                         : "[lockval]" (lockval)
141                         : "memory");
142
143         return (lockval == 0);
144 }
145
146 /**
147  * Test if the lock is taken.
148  *
149  * @param sl
150  *   A pointer to the spinlock.
151  * @return
152  *   1 if the lock is currently taken; 0 otherwise.
153  */
154 static inline int rte_spinlock_is_locked (rte_spinlock_t *sl)
155 {
156         return sl->locked;
157 }
158
159 /**
160  * The rte_spinlock_recursive_t type.
161  */
162 typedef struct {
163         rte_spinlock_t sl; /**< the actual spinlock */
164         volatile int user; /**< core id using lock, -1 for unused */
165         volatile int count; /**< count of time this lock has been called */
166 } rte_spinlock_recursive_t;
167
168 /**
169  * A static recursive spinlock initializer.
170  */
171 #define RTE_SPINLOCK_RECURSIVE_INITIALIZER {RTE_SPINLOCK_INITIALIZER, -1, 0}
172
173 /**
174  * Initialize the recursive spinlock to an unlocked state.
175  *
176  * @param slr
177  *   A pointer to the recursive spinlock.
178  */
179 static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr)
180 {
181         rte_spinlock_init(&slr->sl);
182         slr->user = -1;
183         slr->count = 0;
184 }
185
186 /**
187  * Take the recursive spinlock.
188  *
189  * @param slr
190  *   A pointer to the recursive spinlock.
191  */
192 static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
193 {
194         int id = rte_lcore_id();
195
196         if (slr->user != id) {
197                 rte_spinlock_lock(&slr->sl);
198                 slr->user = id;
199         }
200         slr->count++;
201 }
202 /**
203  * Release the recursive spinlock.
204  *
205  * @param slr
206  *   A pointer to the recursive spinlock.
207  */
208 static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
209 {
210         if (--(slr->count) == 0) {
211                 slr->user = -1;
212                 rte_spinlock_unlock(&slr->sl);
213         }
214
215 }
216
217 /**
218  * Try to take the recursive lock.
219  *
220  * @param slr
221  *   A pointer to the recursive spinlock.
222  * @return
223  *   1 if the lock is successfully taken; 0 otherwise.
224  */
225 static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
226 {
227         int id = rte_lcore_id();
228
229         if (slr->user != id) {
230                 if (rte_spinlock_trylock(&slr->sl) == 0)
231                         return 0;
232                 slr->user = id;
233         }
234         slr->count++;
235         return 1;
236 }
237
238 #ifdef __cplusplus
239 }
240 #endif
241
242 #endif /* _RTE_SPINLOCK_H_ */