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