os_spinlock.c
2026/7/19大约 4 分钟附录源码附录
os_spinlock.c
路径: kernel\source\os_spinlock.c
/**
***********************************************************************************************************************
* Copyright (c) 2020, China Mobile Communications Group Co.,Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @file os_spinlock.c
*
* @brief This file implements the spinlock functions.
*
* @revision
* Date Author Notes
* 2021-01-08 OneOS Team First version.
***********************************************************************************************************************
*/
#include <oneos_config.h>
#include <os_types.h>
#include <os_stddef.h>
#include <os_task.h>
#include <arch_interrupt.h>
#include <os_assert.h>
#include <os_spinlock.h>
#include "os_kernel_internal.h"
void os_spin_lock_init(os_spinlock_t *lock)
{
OS_ASSERT((lock != OS_NULL));
#ifdef OS_USING_SMP
arch_spin_lock_init(&lock->arch_lock);
#endif
#ifdef OS_USING_SPINLOCK_CHECK
lock->owner_cpu = -1;
lock->object_inited = OS_SPINLOCK_INIT_FLAG;
lock->owner = OS_NULL;
#endif
return;
}
#ifdef OS_USING_SPINLOCK_CHECK
OS_INLINE void _k_spin_lock_dbg(os_spinlock_t *lock)
{
os_task_t *task;
OS_ASSERT(OS_SPINLOCK_INIT_FLAG == lock->object_inited);
task = _k_task_self();
if (OS_NULL != task)
{
OS_ASSERT_EX(*((volatile void **)(&lock->owner)) != (void *)task,
"Task[%s] spinlock recursion\r\n",
task->name);
#ifdef OS_USING_SMP
OS_ASSERT_EX((*((volatile int32_t *)(&lock->owner_cpu))) != os_cpu_id_get(),
"[%d]Cpu[%d] spinlock recursion task[%s]",
(*((volatile uint32_t *)(&lock->owner_cpu))),
os_cpu_id_get(),
task->name);
#endif
}
return;
}
OS_INLINE void _k_spin_unlock_dbg(os_spinlock_t *lock)
{
os_task_t *task;
task = _k_task_self();
if (OS_NULL != task)
{
OS_ASSERT_EX((*((volatile void **)(&lock->owner))) == ((void *)task),
"Spinlock owner[%s] is not current[%s]\n",
(OS_NULL == lock->owner) ? "none" : ((os_task_t *)lock->owner)->name,
task->name);
#ifdef OS_USING_SMP
OS_ASSERT_EX((*((volatile int32_t *)(&lock->owner_cpu))) == os_cpu_id_get(),
"Spinlock owner cpu[%d] is not current cpu[%d], owner[%s] current[%s]",
lock->owner_cpu,
os_cpu_id_get(),
(OS_NULL == lock->owner) ? "none" : ((os_task_t *)lock->owner)->name,
task->name);
#endif
}
return;
}
OS_INLINE void _k_spin_lock_set_owner(os_spinlock_t *lock)
{
os_task_t *task;
task = _k_task_self();
if (OS_NULL != task)
{
*((volatile void **)(&lock->owner)) = (void *)task;
#ifdef OS_USING_SMP
*((int32_t *)(&lock->owner_cpu)) = os_cpu_id_get();
#else
*((int32_t *)(&lock->owner_cpu)) = 0;
#endif
}
return;
}
OS_INLINE void _k_spin_lock_cancel_owner(os_spinlock_t *lock)
{
*(volatile void **)(&lock->owner) = OS_NULL;
*(volatile int32_t *)(&lock->owner_cpu) = -1;
return;
}
#endif /* OS_USING_SPINLOCK_CHECK */
/**
***********************************************************************************************************************
* @brief This function locks the spin lock referred to by lock.
*
* @details If the spin lock is currently unlocked, the calling task acquires the lock immediately.
* If the spin lock is currently locked by another task, the calling task spins,
* testing the lock until it becomes available, at which point the calling task acquires the lock.
*
* @attention Calling os_spin_lock_schedulelock() on a lock that is already held by the caller or
* a lock that has not been initialized with os_spin_lock_init results in undefined behavior.
* This function disables interrupts, which is suitable for situations where there is
* no scheduling point between locks.For example, calling os_sem_post() between locks cannot use it.
*
* @param[in] lock The spin lock.
*
* @return None
***********************************************************************************************************************
*/
void os_spin_lock(os_spinlock_t *lock)
{
OS_ASSERT((lock != OS_NULL));
os_schedule_lock();
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_dbg(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_lock(&lock->arch_lock);
#endif
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return;
}
os_bool_t os_spin_trylock(os_spinlock_t *lock)
{
OS_ASSERT((lock != OS_NULL));
os_schedule_lock();
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_dbg(lock);
#endif
#ifdef OS_USING_SMP
if (arch_spin_trylock(&lock->arch_lock) == OS_TRUE)
{
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return OS_TRUE;
}
else
{
os_schedule_unlock();
return OS_FALSE;
}
#else
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return OS_TRUE;
#endif
}
void os_spin_unlock(os_spinlock_t *lock)
{
OS_ASSERT((lock != OS_NULL));
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_unlock_dbg(lock);
_k_spin_lock_cancel_owner(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_unlock(&lock->arch_lock);
#endif
os_schedule_unlock();
return;
}
/**
***********************************************************************************************************************
* @brief This function locks the spin lock referred to by lock.
*
* @details If the spin lock is currently unlocked, the calling task acquires the lock immediately.
* If the spin lock is currently locked by another task, the calling task spins,
* testing the lock until it becomes available, at which point the calling task acquires the lock.
*
* @attention Calling os_spin_lock_schedulelock() on a lock that is already held by the caller or
* a lock that has not been initialized with os_spin_lock_init results in undefined behavior.
* This function locks scheduling, suitable for task context.
*
* @param[in] lock The spin lock.
*
* @return None
***********************************************************************************************************************
*/
void os_spin_lock_irqsave(os_spinlock_t *lock, os_ubase_t *irq_save)
{
OS_ASSERT((lock != OS_NULL));
OS_ASSERT((irq_save != OS_NULL));
*irq_save = os_irq_lock();
os_schedule_lock();
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_dbg(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_lock(&lock->arch_lock);
#endif
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return;
}
void os_spin_unlock_irqrestore(os_spinlock_t *lock, os_ubase_t irq_save)
{
OS_ASSERT((lock != OS_NULL));
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_unlock_dbg(lock);
_k_spin_lock_cancel_owner(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_unlock(&lock->arch_lock);
#endif
os_irq_unlock(irq_save);
os_schedule_unlock();
return;
}
/**
***********************************************************************************************************************
* @brief This function locks the spin lock referred to by lock.
*
* @details If the spin lock is currently unlocked, the calling task acquires the lock immediately.
* If the spin lock is currently locked by another task, the calling task spins,
* testing the lock until it becomes available, at which point the calling task acquires the lock.
*
* @attention Calling os_spin_lock() on a lock that is already held by the caller or
* a lock that has not been initialized with os_spin_lock_init() results in undefined behavior.
* This function disables interrupts and locks scheduling, suitable for any context.
*
* @param[in] lock The spin lock.
*
* @return None
***********************************************************************************************************************
*/
void os_spin_lock_irq(os_spinlock_t *lock, os_ubase_t *irq_save)
{
OS_ASSERT((lock != OS_NULL));
OS_ASSERT((irq_save != OS_NULL));
*irq_save = os_irq_lock();
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_dbg(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_lock(&lock->arch_lock);
#endif
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return;
}
/**
***********************************************************************************************************************
* @brief This function locks the spin lock referred to by lock.
*
* @details This operation is real-time spin lock. This function always disables the interrupt
* and tries to acquire the spin lock, and enables the interrupt when the lock fails,
* so as to avoid always disabling the interrupt when acquiring the spin lock.
*
* @param[in] lock The spin lock.
*
* @return None
***********************************************************************************************************************
*/
void os_spin_lock_irq_rt(os_spinlock_t *lock, os_ubase_t *irq_save)
{
OS_ASSERT((lock != OS_NULL));
OS_ASSERT((irq_save != OS_NULL));
while (1)
{
*irq_save = os_irq_lock();
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_dbg(lock);
#endif
#ifdef OS_USING_SMP
if (arch_spin_trylock(&lock->arch_lock) == OS_TRUE)
{
break;
}
else
{
os_irq_unlock(*irq_save);
}
#else
break;
#endif
}
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return;
}
void os_spin_unlock_irq(os_spinlock_t *lock, os_ubase_t irq_save)
{
OS_ASSERT((lock != OS_NULL));
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_unlock_dbg(lock);
_k_spin_lock_cancel_owner(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_unlock(&lock->arch_lock);
#endif
os_irq_unlock(irq_save);
return;
}
void os_spin_lock_irq_disable(os_spinlock_t *lock)
{
OS_ASSERT((lock != OS_NULL));
os_irq_disable();
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_dbg(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_lock(&lock->arch_lock);
#endif
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_lock_set_owner(lock);
#endif
return;
}
void os_spin_unlock_irq_enable(os_spinlock_t *lock)
{
OS_ASSERT((lock != OS_NULL));
#ifdef OS_USING_SPINLOCK_CHECK
_k_spin_unlock_dbg(lock);
_k_spin_lock_cancel_owner(lock);
#endif
#ifdef OS_USING_SMP
arch_spin_unlock(&lock->arch_lock);
#endif
os_irq_enable();
return;
}