1 /*----------------------------------------------------------------------------
2 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
3 * Description: Spinlock
4 * Author: Huawei LiteOS Team
5 * Create: 2018-07-11
6 * Redistribution and use in source and binary forms, with or without modification,
7 * are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without specific prior written
15 * permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *---------------------------------------------------------------------------*/
28
29 /**
30 * @defgroup los_spinlock Spinlock
31 * @ingroup kernel
32 */
33
34 #ifndef _LOS_SPINLOCK_H
35 #define _LOS_SPINLOCK_H
36 #include "los_typedef.h"
37 #include "los_config.h"
38 #include "los_hwi.h"
39 #include "los_task.h"
40 #include "los_lockdep.h"
41 #include "arch/spinlock.h"
42
43 #ifdef __cplusplus
44 extern "C" {
45 #endif /* __cplusplus */
46
47 #ifdef LOSCFG_KERNEL_SPINDEP
48 #define OS_SPINLOCK_FROM_SPINLOCK_CHECK(ptr) LOS_DL_LIST_ENTRY(ptr, SPIN_LOCK_S, lockCheck)
49 #define SPIN_LOCK_INITIALIZER(lockName) \
50 {0U, {LOCK_SPIN, 0, #lockName, 0xFFFFFFFF, NULL}}
51 #else
52 #define SPIN_LOCK_INITIALIZER(lockName) \
53 { \
54 .rawLock = 0U, \
55 }
56 #endif
57
58 /**
59 * @ingroup los_spinlock
60 * <ul>
61 * <li>This macro is used to define the input parameter lock as a spinlock, and initialize the
62 * spinlock statically.</li>
63 * <li>This macro has no return value.</li>
64 * <li>Note that the input parameter lock does not need to be defined before calling this macro.
65 * Otherwise, the variable lock is repeatedly defined.</li>
66 * <li>On Non-SMP (UP) mode, this macro has no effect.</li>
67 * <li>The spinlock is advised to protect operation that take a short time. Otherwise, the overall system
68 * performance may be affected because the thread exits the waiting loop only after the spinlock is
69 * obtained. For time-consuming operation, the mutex lock can be used instead of spinlock.</li>
70 * </ul>
71 */
72 #define SPIN_LOCK_INIT(lock) SPIN_LOCK_S lock = SPIN_LOCK_INITIALIZER(lock)
73
74 /**
75 * @ingroup los_spinlock
76 * Define the structure of spinlock.
77 */
78 struct Spinlock {
79 size_t rawLock; /**< raw spinlock */
80 #ifdef LOSCFG_KERNEL_SPINDEP
81 LosLockCheck lockCheck; /**< lock check entity */
82 #endif
83 };
84 typedef struct Spinlock SPIN_LOCK_S;
85 #ifdef LOSCFG_KERNEL_SMP
86 /**
87 * @ingroup los_spinlock
88 * @brief Lock the spinlock.
89 *
90 * @par Description:
91 * This API is used to lock the spinlock. If the spinlock has been obtained by another thread,
92 * the thread will wait cyclically until it can lock the spinlock successfully.
93 *
94 * @attention
95 * <ul>
96 * <li>The spinlock must be initialized before it is used. It should be initialized by #LOS_SpinInit
97 * or #SPIN_LOCK_INIT.</li>
98 * <li>The parameter passed in should be a legal pointer.</li>
99 * <li>A spinlock can not be locked for multiple times in a task. Otherwise, a deadlock occurs.</li>
100 * <li>If the spinlock will be used in both task and interrupt, using #LOS_SpinLockSave instead of
101 * this API.</li>
102 * <li>On Non-SMP (UP) mode, this function has no effect.</li>
103 * </ul>
104 *
105 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
106 *
107 * @retval None.
108 * @par Dependency:
109 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
110 * @see LOS_SpinTrylock | LOS_SpinLockSave | LOS_SpinUnlock | LOS_SpinUnlockNoSched | SPIN_LOCK_INIT | LOS_SpinInit
111 * @since Huawei LiteOS V200R003C00
112 */
LOS_SpinLock(SPIN_LOCK_S * lock)113 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLock(SPIN_LOCK_S *lock)
114 {
115 /*
116 * disable the scheduler, so it won't do schedule until
117 * scheduler is reenabled. The LOS_TaskUnlock should not
118 * be directly called along this critic area.
119 */
120 LOS_TaskLock();
121
122 LOCKDEP_CHECK_IN(lock);
123 ArchSpinLock(&lock->rawLock);
124 LOCKDEP_RECORD(lock);
125 }
126
127 /**
128 * @ingroup los_spinlock
129 * @brief Trying to lock the spinlock.
130 *
131 * @par Description:
132 * This API is used to try to lock the spinlock. If the spinlock has been obtained by another thread,
133 * this API will not waiting for the lock's owner to release the spinlock and return the failure directly.
134 *
135 * @attention
136 * <ul>
137 * <li>The spinlock must be initialized before it is used. It should be initialized by #LOS_SpinInit
138 * or #SPIN_LOCK_INIT.</li>
139 * <li>The parameter passed in should be a legal pointer.</li>
140 * <li>A spinlock can not be locked for multiple times in a task. Otherwise, a deadlock occurs.</li>
141 * <li>On Non-SMP (UP) mode, this function has no effect.</li>
142 * </ul>
143 *
144 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
145 *
146 * @retval #LOS_OK Got the spinlock.
147 * @retval #LOS_NOK Failed to get the spinlock.
148 * @par Dependency:
149 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
150 * @see LOS_SpinLock | LOS_SpinLockSave | LOS_SpinUnlock | LOS_SpinUnlockNoSched | SPIN_LOCK_INIT | LOS_SpinInit
151 * @since Huawei LiteOS V200R003C00
152 */
LOS_SpinTrylock(SPIN_LOCK_S * lock)153 LITE_OS_SEC_ALW_INLINE STATIC INLINE INT32 LOS_SpinTrylock(SPIN_LOCK_S *lock)
154 {
155 LOS_TaskLock();
156
157 LOCKDEP_CHECK_IN(lock);
158 INT32 ret = ArchSpinTrylock(&lock->rawLock);
159 if (ret == LOS_OK) {
160 LOCKDEP_RECORD(lock);
161 }
162
163 return ret;
164 }
165
166 /**
167 * @ingroup los_spinlock
168 * @brief Unlock the spinlock.
169 *
170 * @par Description:
171 * This API is used to unlock the spin lock.
172 *
173 * @attention
174 * <ul>
175 * <li>The parameter passed in should be a legal pointer.</li>
176 * <li>On Non-SMP (UP) mode, this function has no effect. </li>
177 * </ul>
178 *
179 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
180 *
181 * @retval None.
182 * @par Dependency:
183 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
184 * @see LOS_SpinLock | LOS_SpinTrylock | LOS_SpinLockSave | LOS_SpinUnlockRestore
185 * @since Huawei LiteOS V200R003C00
186 */
LOS_SpinUnlock(SPIN_LOCK_S * lock)187 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
188 {
189 LOCKDEP_CHECK_OUT(lock);
190 ArchSpinUnlock(&lock->rawLock);
191
192 /* Restore the scheduler flag. May cause task schedule. */
193 LOS_TaskUnlock();
194 }
195
196 /**
197 * @ingroup los_spinlock
198 * @brief Unlock the spinlock and no scheduling is generated.
199 *
200 * @par Description:
201 * This API is used to unlock the spin lock without scheduling.
202 *
203 * @attention
204 * <ul>
205 * <li>The parameter passed in should be a legal pointer.</li>
206 * <li>On Non-SMP (UP) mode, this function has no effect.</li>
207 * <li>Unlocking does not generate scheduling. Therefore, there is a delay for waiting tasks to be scheduled.
208 * Users needs proactive scheduling to ensure timing.</li>
209 * <li> For example, this function can be used in spin lock switching, make sure the first spin unlock not trigger
210 * unnecessary scheduling. Then, the second spin lock invokes LOS_SpinUnlock to ensure scheduling.</li>
211 * </ul>
212 *
213 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
214 *
215 * @retval None.
216 * @par Dependency:
217 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
218 * @see LOS_SpinLock | LOS_SpinTrylock | LOS_SpinLockSave
219 * @since Huawei LiteOS 207.0.0
220 */
LOS_SpinUnlockNoSched(SPIN_LOCK_S * lock)221 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlockNoSched(SPIN_LOCK_S *lock)
222 {
223 LOCKDEP_CHECK_OUT(lock);
224 ArchSpinUnlock(&lock->rawLock);
225
226 /* Restore the scheduler flag only. */
227 LOS_TaskUnlockNoSched();
228 }
229
230 /**
231 * @ingroup los_spinlock
232 * @brief Lock the spinlock and disable all interrupts.
233 *
234 * @par Description:
235 * This API is used to lock the spinlock and disable all interrupts before locking. After
236 * the interrupts are disabled, this API executes exactly the same as #LOS_SpinLock.
237 * @attention
238 * <ul>
239 * <li>The spinlock must be initialized before it is used. It should be initialized by
240 * #LOS_SpinInit or #SPIN_LOCK_INIT.</li>
241 * <li>The parameter passed in should be a legal pointer.</li>
242 * <li>A spinlock can not be locked for multiple times in a task. Otherwise, a deadlock
243 * occurs.</li>
244 * <li>On Non-SMP (UP) mode, this function only disables all interrupts.</li>
245 * </ul>
246 *
247 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
248 * @param intSave [OUT] Type #UINT32 The pointer is used to save the interrupt flag
249 * before all interrupts are disabled. It will be
250 * used by #LOS_SpinUnlockRestore.
251 *
252 * @retval None.
253 * @par Dependency:
254 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
255 * @see LOS_SpinLock | LOS_SpinTrylock | LOS_SpinUnlockRestore
256 * @since Huawei LiteOS V200R003C00
257 */
LOS_SpinLockSave(SPIN_LOCK_S * lock,UINT32 * intSave)258 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
259 {
260 *intSave = LOS_IntLock();
261 LOS_SpinLock(lock);
262 }
263
264 /**
265 * @ingroup los_spinlock
266 * @brief Unlock the spinlock and restore the interrupt flag.
267 *
268 * @par Description:
269 * This API is used to unlock the spinlock and restore the interrupts by restoring the interrupt flag.
270 * This API can be called only after calling #LOS_SpinLockSave, and the input parameter value should
271 * be the parameter returned by #LOS_SpinLockSave.
272 *
273 * @attention
274 * <ul>
275 * <li>The parameter passed in should be a legal pointer.</li>
276 * <li>On Non-SMP (UP) mode, this function only restore interrupt flag.</li>
277 * </ul>
278 *
279 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
280 * @param intSave [IN] Type #UINT32 The interrupt flag need to be restored.
281 *
282 * @retval None.
283 * @par Dependency:
284 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
285 * @see LOS_SpinUnlock | LOS_SpinLockSave
286 * @since Huawei LiteOS V200R003C00
287 */
LOS_SpinUnlockRestore(SPIN_LOCK_S * lock,UINT32 intSave)288 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
289 {
290 LOS_SpinUnlock(lock);
291 LOS_IntRestore(intSave);
292 }
293
294 /**
295 * @ingroup los_spinlock
296 * @brief Check if holding the spinlock.
297 *
298 * @par Description:
299 * This API is used to check if the spinlock is held or not.
300 *
301 * @attention
302 * <ul>
303 * <li>The parameter passed in should be a legal pointer.</li>
304 * <li>On Non-SMP (UP) mode, this function always returns #TRUE.</li>
305 * </ul>
306 *
307 * @param lock [IN] Type #SPIN_LOCK_S The pointer to spinlock.
308 *
309 * @retval #TRUE The spinlock is held.
310 * @retval #FALSE The spinlock is not held.
311 * @par Dependency:
312 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
313 * @since Huawei LiteOS V200R003C00
314 */
LOS_SpinHeld(const SPIN_LOCK_S * lock)315 LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_SpinHeld(const SPIN_LOCK_S *lock)
316 {
317 return (lock->rawLock != 0);
318 }
319
320 /**
321 * @ingroup los_spinlock
322 * @brief Spinlock dynamic initialization.
323 *
324 * @par Description:
325 * This API is used to initialize a spinlock dynamically.
326 *
327 * @attention
328 * <ul>
329 * <li>The spinlock is advised to protect operation that take a short time. Otherwise, the overall system
330 * performance may be affected because the thread exits the waiting loop only after the spinlock is
331 * obtained. For time-consuming operation, the mutex lock can be used instead of spinlock.</li>
332 * <li>The parameter passed in should be a legal pointer.</li>
333 * <li>On Non-SMP (UP) mode, this function has no effect.</li>
334 * </ul>
335 *
336 * @param lock [IN/OUT] Type #SPIN_LOCK_S The pointer to spinlock need to be initialized.
337 *
338 * @retval None.
339 *
340 * @par Dependency:
341 * <ul><li>los_spinlock.h: the header file that contains the API declaration.</li></ul>
342 * @since Huawei LiteOS V200R003C00
343 */
LOS_SpinInit(SPIN_LOCK_S * lock)344 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinInit(SPIN_LOCK_S *lock)
345 {
346 lock->rawLock = 0;
347 LOCKDEP_CHECK_INIT(lock);
348 }
349
350 #else
351
352 /*
353 * For Non-SMP system, these apis does not handle with spinlocks,
354 * but for unifying the code of drivers, vendors and etc.
355 */
LOS_SpinLock(SPIN_LOCK_S * lock)356 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLock(SPIN_LOCK_S *lock)
357 {
358 (VOID)lock;
359 }
360
LOS_SpinTrylock(SPIN_LOCK_S * lock)361 LITE_OS_SEC_ALW_INLINE STATIC INLINE INT32 LOS_SpinTrylock(SPIN_LOCK_S *lock)
362 {
363 (VOID)lock;
364 return LOS_OK;
365 }
366
LOS_SpinUnlock(SPIN_LOCK_S * lock)367 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
368 {
369 (VOID)lock;
370 }
371
LOS_SpinUnlockNoSched(SPIN_LOCK_S * lock)372 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlockNoSched(SPIN_LOCK_S *lock)
373 {
374 (VOID)lock;
375 }
376
LOS_SpinLockSave(SPIN_LOCK_S * lock,UINT32 * intSave)377 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
378 {
379 (VOID)lock;
380 *intSave = LOS_IntLock();
381 }
382
LOS_SpinUnlockRestore(SPIN_LOCK_S * lock,UINT32 intSave)383 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
384 {
385 (VOID)lock;
386 LOS_IntRestore(intSave);
387 }
388
LOS_SpinHeld(const SPIN_LOCK_S * lock)389 LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_SpinHeld(const SPIN_LOCK_S *lock)
390 {
391 (VOID)lock;
392 return TRUE;
393 }
394
LOS_SpinInit(SPIN_LOCK_S * lock)395 LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinInit(SPIN_LOCK_S *lock)
396 {
397 (VOID)lock;
398 }
399
400 #endif
401
402 #ifdef __cplusplus
403 }
404 #endif /* __cplusplus */
405
406 #endif
407