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