• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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