os_block.c
2026/7/20大约 4 分钟附录源码附录
os_block.c
路径: kernel\source\os_block.c
功能: 任务阻塞与唤醒的公共函数实现。提供 IPC 机制(信号量、互斥量、消息队列、邮箱等)通用的任务阻塞、唤醒和批量取消阻塞功能。所有 IPC 对象在等待资源时,都通过本文件提供的 k_block_task、k_unblock_task、k_cancel_all_blocked_task 来管理阻塞任务链表。
核心函数:
| 函数 | 说明 |
|---|---|
k_blockq_insert | 按优先级将任务插入 IPC 阻塞队列(高优先级在前) |
k_block_task | 阻塞当前任务:从就绪队列移除 → 插入 IPC 等待队列 → 可选加入 tick 超时队列 → 触发调度 |
k_unblock_task | 唤醒单个任务:从 IPC 等待队列移除 → 从 tick 队列移除 → 恢复就绪 |
k_cancel_all_blocked_task | 批量取消所有阻塞任务(IPC 对象销毁时调用):全部唤醒,设置 switch_retval = OS_FAILURE |
k_show_blocked_task | Shell 辅助函数:打印阻塞任务列表(名称和优先级) |
关键设计点:
- 优先级排队:
k_blockq_insert按优先级插入,高优先级任务排在前面,确保唤醒时高优先级任务优先获取资源 - 超时支持: 非
OS_WAIT_FOREVER的阻塞任务会加入 tick 超时队列,超时后自动唤醒并返回OS_TIMEOUT - SMP 安全: 多核模式下使用
k_kernel_spin_lock保护内核全局状态 - switch_retval: 任务阻塞时通过
task->switch_retval返回阻塞结果(OS_SUCCESS被唤醒、OS_FAILURE被取消、OS_TIMEOUT超时) - 状态管理: 阻塞时清除
OS_TASK_STATE_READY,设置OS_TASK_STATE_BLOCK;有限等待时额外设置OS_TASK_STATE_SLEEP
/**
***********************************************************************************************************************
* 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_ipc.c
*
* @brief This file implements the IPC public functions.
*
* @revision
* Date Author Notes
* 2020-02-11 OneOS team First Version
***********************************************************************************************************************
*/
#include <os_errno.h>
#include <arch_interrupt.h>
#include <os_list.h>
#include <os_task.h>
#include <string.h>
#include "os_kernel_internal.h"
/**
***********************************************************************************************************************
* @brief 将任务按优先级插入 IPC 阻塞队列(高优先级在前)
*
* @param[in] head IPC 等待队列头
* @param[in] task 待插入的任务
***********************************************************************************************************************
*/
void k_blockq_insert(os_list_node_t *head, struct os_task *task)
{
os_list_node_t *pos;
os_task_t *task_iter;
os_list_for_each(pos, head)
{
task_iter = os_list_entry(pos, os_task_t, task_node);
if (task_iter->current_priority > task->current_priority)
{
/* 在更高优先级任务前插入 */
os_list_add_tail(&task_iter->task_node, &task->task_node);
break;
}
}
if (pos == head)
{
os_list_add_tail(head, &task->task_node);
}
return;
}
/**
***********************************************************************************************************************
* @brief 阻塞当前任务
*
* @param[in] lock IPC 对象自旋锁
* @param[in] irq_save 中断保存状态
* @param[in] head IPC 等待队列头
* @param[in] timeout 等待超时时间(tick 数)
* @param[in] is_wake_prio 是否按优先级唤醒(OS_TRUE)还是 FIFO(OS_FALSE)
*
* @return 阻塞结果(通过 task->switch_retval 返回)
***********************************************************************************************************************
*/
/* clang-format off */
os_err_t k_block_task( os_spinlock_t *lock,
os_ubase_t irq_save,
os_list_node_t *head,
os_tick_t timeout,
os_bool_t is_wake_prio)
/* clang-format on */
{
os_task_t *task;
task = _k_task_self();
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#else
OS_UNREFERENCE(lock);
#endif
/* 从就绪队列移除 */
k_readyq_remove(task);
/* 插入 IPC 等待队列(按优先级或 FIFO) */
if (OS_TRUE == is_wake_prio)
{
k_blockq_insert(head, task);
}
else
{
os_list_add_tail(head, &task->task_node);
}
task->state &= ~OS_TASK_STATE_READY;
task->state |= OS_TASK_STATE_BLOCK;
task->block_list_head = head;
task->is_wake_prio = is_wake_prio;
/* 有限等待:加入 tick 超时队列 */
if (OS_WAIT_FOREVER != timeout)
{
task->state |= OS_TASK_STATE_SLEEP;
k_tickq_put(task, timeout);
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
os_spin_unlock_irq(lock, irq_save);
OS_KERNEL_ENTER();
OS_KERNEL_EXIT_SCHED();
#else
OS_KERNEL_EXIT_SCHED();
#endif
return task->switch_retval;
}
/**
***********************************************************************************************************************
* @brief 唤醒单个阻塞任务
*
* @param[in] task 待唤醒的任务
*
* @return 是否需要调度(OS_TRUE/OS_FALSE)
***********************************************************************************************************************
*/
os_bool_t k_unblock_task(os_task_t *task)
{
os_bool_t need_sched;
/* 从 IPC 等待队列移除 */
os_list_del(&task->task_node);
task->state &= ~OS_TASK_STATE_BLOCK;
task->block_list_head = OS_NULL;
task->switch_retval = OS_SUCCESS;
/* 从 tick 超时队列移除 */
if ((task->state & OS_TASK_STATE_SLEEP) != 0)
{
k_tickq_remove(task);
task->state &= ~OS_TASK_STATE_SLEEP;
}
/* 如果任务未被挂起,恢复就绪 */
if (OS_TASK_STATE_SUSPEND != task->state)
{
task->state |= OS_TASK_STATE_READY;
k_readyq_put(task);
need_sched = OS_TRUE;
}
else
{
need_sched = OS_FALSE;
}
return need_sched;
}
/**
***********************************************************************************************************************
* @brief 批量取消所有阻塞任务(IPC 对象销毁时调用)
*
* @param[in] head IPC 等待队列头
*
* @return 是否需要调度
***********************************************************************************************************************
*/
os_bool_t k_cancel_all_blocked_task(const os_list_node_t *head)
{
os_task_t *task;
os_bool_t need_sched;
need_sched = OS_FALSE;
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_lock();
#endif
while (!os_list_empty(head))
{
task = os_list_first_entry(head, os_task_t, task_node);
os_list_del(&task->task_node);
task->state &= ~OS_TASK_STATE_BLOCK;
task->block_list_head = OS_NULL;
if ((task->state & OS_TASK_STATE_SLEEP) != 0)
{
k_tickq_remove(task);
task->state &= ~OS_TASK_STATE_SLEEP;
}
if (OS_TASK_STATE_SUSPEND != task->state)
{
task->state |= OS_TASK_STATE_READY;
k_readyq_put(task);
need_sched = OS_TRUE;
}
/* 被取消的任务返回 OS_FAILURE */
task->switch_retval = OS_FAILURE;
}
#if defined(OS_USING_SMP) && !defined(OS_IPC_MONOLOCK_MODE)
k_kernel_spin_unlock();
#endif
return need_sched;
}
#ifdef OS_USING_SHELL
#include <shell.h>
/* Shell 辅助函数:打印阻塞任务列表 */
void k_show_blocked_task(block_task_info_t *info, uint16_t block_task_cnt)
{
uint16_t i;
uint16_t j;
char name[OS_NAME_MAX + 1];
name[OS_NAME_MAX] = '\0';
for (i = 0; i < block_task_cnt; i++)
{
for (j = 0; j < OS_NAME_MAX; j++)
{
name[j] = info[i].name[j];
if (name[j] == '\0')
{
break;
}
}
os_kprintf("%s(%d)", (name[0] != '\0') ? name : "-", info[i].current_priority);
if (i != block_task_cnt - 1)
{
os_kprintf("/");