spinlock: support non-EAL thread
[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
55 /**
56  * The rte_spinlock_t type.
57  */
58 typedef struct {
59         volatile int locked; /**< lock status 0 = unlocked, 1 = locked */
60 } rte_spinlock_t;
61
62 /**
63  * A static spinlock initializer.
64  */
65 #define RTE_SPINLOCK_INITIALIZER { 0 }
66
67 /**
68  * Initialize the spinlock to an unlocked state.
69  *
70  * @param sl
71  *   A pointer to the spinlock.
72  */
73 static inline void
74 rte_spinlock_init(rte_spinlock_t *sl)
75 {
76         sl->locked = 0;
77 }
78
79 /**
80  * Take the spinlock.
81  *
82  * @param sl
83  *   A pointer to the spinlock.
84  */
85 static inline void
86 rte_spinlock_lock(rte_spinlock_t *sl);
87
88 #ifdef RTE_FORCE_INTRINSICS
89 static inline void
90 rte_spinlock_lock(rte_spinlock_t *sl)
91 {
92         while (__sync_lock_test_and_set(&sl->locked, 1))
93                 while(sl->locked)
94                         rte_pause();
95 }
96 #endif
97
98 /**
99  * Release the spinlock.
100  *
101  * @param sl
102  *   A pointer to the spinlock.
103  */
104 static inline void
105 rte_spinlock_unlock (rte_spinlock_t *sl);
106
107 #ifdef RTE_FORCE_INTRINSICS
108 static inline void
109 rte_spinlock_unlock (rte_spinlock_t *sl)
110 {
111         __sync_lock_release(&sl->locked);
112 }
113 #endif
114
115 /**
116  * Try to take the lock.
117  *
118  * @param sl
119  *   A pointer to the spinlock.
120  * @return
121  *   1 if the lock is successfully taken; 0 otherwise.
122  */
123 static inline int
124 rte_spinlock_trylock (rte_spinlock_t *sl);
125
126 #ifdef RTE_FORCE_INTRINSICS
127 static inline int
128 rte_spinlock_trylock (rte_spinlock_t *sl)
129 {
130         return (__sync_lock_test_and_set(&sl->locked,1) == 0);
131 }
132 #endif
133
134 /**
135  * Test if the lock is taken.
136  *
137  * @param sl
138  *   A pointer to the spinlock.
139  * @return
140  *   1 if the lock is currently taken; 0 otherwise.
141  */
142 static inline int rte_spinlock_is_locked (rte_spinlock_t *sl)
143 {
144         return sl->locked;
145 }
146
147 /**
148  * The rte_spinlock_recursive_t type.
149  */
150 typedef struct {
151         rte_spinlock_t sl; /**< the actual spinlock */
152         volatile int user; /**< core id using lock, -1 for unused */
153         volatile int count; /**< count of time this lock has been called */
154 } rte_spinlock_recursive_t;
155
156 /**
157  * A static recursive spinlock initializer.
158  */
159 #define RTE_SPINLOCK_RECURSIVE_INITIALIZER {RTE_SPINLOCK_INITIALIZER, -1, 0}
160
161 /**
162  * Initialize the recursive spinlock to an unlocked state.
163  *
164  * @param slr
165  *   A pointer to the recursive spinlock.
166  */
167 static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr)
168 {
169         rte_spinlock_init(&slr->sl);
170         slr->user = -1;
171         slr->count = 0;
172 }
173
174 /**
175  * Take the recursive spinlock.
176  *
177  * @param slr
178  *   A pointer to the recursive spinlock.
179  */
180 static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
181 {
182         int id = rte_gettid();
183
184         if (slr->user != id) {
185                 rte_spinlock_lock(&slr->sl);
186                 slr->user = id;
187         }
188         slr->count++;
189 }
190 /**
191  * Release the recursive spinlock.
192  *
193  * @param slr
194  *   A pointer to the recursive spinlock.
195  */
196 static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
197 {
198         if (--(slr->count) == 0) {
199                 slr->user = -1;
200                 rte_spinlock_unlock(&slr->sl);
201         }
202
203 }
204
205 /**
206  * Try to take the recursive lock.
207  *
208  * @param slr
209  *   A pointer to the recursive spinlock.
210  * @return
211  *   1 if the lock is successfully taken; 0 otherwise.
212  */
213 static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
214 {
215         int id = rte_gettid();
216
217         if (slr->user != id) {
218                 if (rte_spinlock_trylock(&slr->sl) == 0)
219                         return 0;
220                 slr->user = id;
221         }
222         slr->count++;
223         return 1;
224 }
225
226 #endif /* _RTE_SPINLOCK_H_ */