os_kernel_lock.c 源码
2026/7/20大约 2 分钟源码参考内核内核锁SMP
os_kernel_lock.c — 内核锁机制
源文件路径: kernel/source/os_kernel_lock.c
引用章节: 4.2.8 调度器锁定
核心机制
内核锁(Kernel Lock)是 OneOS 保护内核临界区的核心机制:
- SMP 模式:使用架构自旋锁 + 中断禁用,防止多核同时进入内核
- 单核模式:使用递归计数 + 断言检测,防止错误的嵌套进入/退出
完整源码
/**
***********************************************************************************************************************
* 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_kernel_lock.c
*
* @brief This file implements the operations of kernel lock.
*
* @revision
* Date Author Notes
* 2020-10-13 OneOS Team First Version
***********************************************************************************************************************
*/
#include <oneos_config.h>
#include <os_types.h>
#include <os_stddef.h>
#include <os_assert.h>
#include <os_errno.h>
#include <os_spinlock.h>
#include <arch_interrupt.h>
#include "os_kernel_internal.h"
#ifdef OS_USING_SMP
struct kernel_lock
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
int32_t cpu_index; /*cpu + 1*/
#endif
arch_spinlock_t lock;
};
static struct kernel_lock gs_os_kernel_lock = {
#ifdef OS_USING_KERNEL_LOCK_CHECK
.cpu_index = 0,
#endif
.lock = ARCH_SPINLOCK_INIT_VALUE(SPINLOCK_ARCH_UNLOCKED),
};
/**
* @brief 进入内核临界区(SMP 版本)
* 先关中断,再获取自旋锁
* @return 中断保存状态
*/
os_ubase_t k_kernel_enter(void)
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
int32_t current_cpu_index;
#endif
register os_ubase_t irq_save;
irq_save = os_irq_lock();
#ifdef OS_USING_KERNEL_LOCK_CHECK
current_cpu_index = os_cpu_id_get();
OS_ASSERT_EX(gs_os_kernel_lock.cpu_index != (current_cpu_index + 1),
"Kernel lock owner nest");
#endif
arch_spin_lock(&gs_os_kernel_lock.lock);
#ifdef OS_USING_KERNEL_LOCK_CHECK
gs_os_kernel_lock.cpu_index = current_cpu_index + 1;
#endif
return irq_save;
}
/**
* @brief 退出内核临界区(SMP 版本)
* 先释放自旋锁,再恢复中断
*/
void k_kernel_exit(os_ubase_t irq_save)
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
OS_ASSERT_EX(gs_os_kernel_lock.cpu_index == (os_cpu_id_get() + 1),
"Kernel lock owner nest");
gs_os_kernel_lock.cpu_index = 0;
#endif
arch_spin_unlock(&gs_os_kernel_lock.lock);
os_irq_unlock(irq_save);
}
/* k_kernel_spin_lock / k_kernel_spin_unlock: 不关中断的版本 */
void k_kernel_spin_lock(void)
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
int32_t current_cpu_index = os_cpu_id_get();
OS_ASSERT_EX(gs_os_kernel_lock.cpu_index != (current_cpu_index + 1),
"Kernel lock owner nest");
#endif
arch_spin_lock(&gs_os_kernel_lock.lock);
#ifdef OS_USING_KERNEL_LOCK_CHECK
gs_os_kernel_lock.cpu_index = current_cpu_index + 1;
#endif
}
void k_kernel_spin_unlock(void)
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
int32_t current_cpu_index = os_cpu_id_get();
OS_ASSERT_EX(gs_os_kernel_lock.cpu_index == (current_cpu_index + 1),
"Kernel lock owner nest");
gs_os_kernel_lock.cpu_index = 0;
#endif
arch_spin_unlock(&gs_os_kernel_lock.lock);
}
#else /* !OS_USING_SMP -- 单核模式 */
int32_t g_os_kernel_lock_cnt = 0;
/**
* @brief 进入内核临界区检测(单核版本)
* 使用递归计数防止错误嵌套
*/
void k_kernel_enter_check(void)
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
os_bool_t fault_active = os_is_fault_active();
if (OS_NULL != g_os_current_task)
{
if (OS_TRUE == fault_active)
{
/* 异常上下文:不做检测 */
}
else
{
OS_ASSERT_EX(0 == g_os_kernel_lock_cnt,
"Kernel enter check failed, task(%s), irq(%u), ref_cnt(%d)",
g_os_current_task->name,
os_irq_num(),
g_os_kernel_lock_cnt);
g_os_kernel_lock_cnt++;
}
}
#endif
}
/**
* @brief 退出内核临界区检测(单核版本)
*/
void k_kernel_exit_check(void)
{
#ifdef OS_USING_KERNEL_LOCK_CHECK
os_bool_t fault_active = os_is_fault_active();
if (OS_NULL != g_os_current_task)
{
if (OS_TRUE == fault_active)
{
/* 异常上下文:不做检测 */
}
else
{
OS_ASSERT_EX(1 == g_os_kernel_lock_cnt,
"Kernel exit check failed, task(%s), irq(%u), ref_cnt(%d)",
g_os_current_task->name,
os_irq_num(),
g_os_kernel_lock_cnt);
g_os_kernel_lock_cnt--;
}
}
#endif
}
#endif /* OS_USING_SMP */关键函数说明
| 函数 | 模式 | 行为 |
|---|---|---|
k_kernel_enter | SMP | 关中断 → 获取自旋锁 → 返回 IRQ 状态 |
k_kernel_exit | SMP | 释放自旋锁 → 恢复中断 |
k_kernel_enter_check | 单核 | 断言递归计数=0,然后+1 |
k_kernel_exit_check | 单核 | 断言递归计数=1,然后-1 |