提交 f90f08b9 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

注解LiteIPC(轻量级进程间通信)模块

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 2292c0fc
......@@ -47,20 +47,20 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*!
* @brief 内存屏障(英语:Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,
/*!
* @brief 内存屏障(英语:Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,
\n 它使得 CPU 或编译器在对内存进行操作的时候, 严格按照一定的顺序来执行, 也就是说在memory barrier 之前的指令
\n 和memory barrier之后的指令不会由于系统优化等原因而导致乱序。
\n 大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏障成为必须。
\n 大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏障成为必须。
\n 语义上,内存屏障之前的所有写操作都要写入内存;内存屏障之后的读操作都可以获得同步屏障之前的写操作的结果。
\n 因此,对于敏感的程序块,写操作之后、读操作之前可以插入内存屏障。
*
* @param index
* @return
*
* @see
*/
*
* @param index
* @return
*
* @see
*/
// https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/memory-access-ordering---an-introduction
......
/*!
* @file los_hwi.c
* @brief 硬中断主文件
* @link
* @verbatim
基本概念
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,
这个过程就叫做中断。通过中断机制,可以使CPU避免把大量时间耗费在等待、查询外设状态的操作上,
大大提高系统实时性以及执行效率。
异常处理是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,
例如虚拟内存缺页异常、打印异常发生时函数的调用栈信息、CPU现场信息、任务的堆栈情况等。
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,产生一个中断信号,
该信号连接至中断控制器。中断控制器是一方面接收其它外设中断引脚的输入,另一方面它会发出中断信号给CPU。
可以通过对中断控制器编程来打开和关闭中断源、设置中断源的优先级和触发方式。
常用的中断控制器有VIC(Vector Interrupt Controller)和GIC(General Interrupt Controller)。
在ARM Cortex-A7中使用的中断控制器是GIC。CPU收到中断控制器发送的中断信号后,中断当前任务来响应中断请求。
异常处理就是可以打断CPU正常运行流程的一些事情,如未定义指令异常、试图修改只读的数据异常、不对齐的地址访问异常等。
当异常发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被异常打断的程序。
中断特性:
中断共享,且可配置。
中断嵌套,即高优先级的中断可抢占低优先级的中断,且可配置。
使用独立中断栈,可配置。
可配置支持的中断优先级个数。
可配置支持的中断数。
中断相关的硬件介绍
与中断相关的硬件可以划分为三类:设备、中断控制器、CPU本身。
设备
发起中断的源,当设备需要请求CPU时,产生一个中断信号,该信号连接至中断控制器。
中断控制器
中断控制器是CPU众多外设中的一个,它一方面接收其它外设中断引脚的输入,另一方面,
它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源
的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和
GIC(General Interrupt Controller)。在ARM Cortex-M系列中使用的中断控制器是
NVIC(Nested Vector Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。
CPU
CPU会响应中断源的请求,中断当前正在执行的任务,转而执行中断处理程序。
中断相关概念
中断号
每个中断请求信号都会有特定的标志,使得计算机能够判断是哪个设备提出的中断请求,这个标志就是中断号。
中断请求
“紧急事件”需向CPU提出申请(发一个电脉冲信号),要求中断,及要求CPU暂停当前执行的任务,
转而处理该“紧急事件”,这一申请过程称为中断请求。
中断优先级
为使系统能够及时响应并处理所有中断,系统根据中断时间的重要性和紧迫程度,将中断源分为若干个级别,
称作中断优先级。
中断处理程序
当外设产生中断请求后,CPU暂停当前的任务,转而响应中断申请,即执行中断处理程序。产生中断的每个设备
都有相应的中断处理程序。
中断嵌套
中断嵌套也称为中断抢占,指的是正在执行一个中断处理程序时,如果有另一个优先级更高的中断源提出中断请求,
这时会暂时终止当前正在执行的优先级较低的中断源的中断处理程序,转而去处理更高优先级的中断请求,待处理完毕,
再返回到之前被中断的处理程序中继续执行。
中断触发
中断源向中断控制器发送中断信号,中断控制器对中断进行仲裁,确定优先级,将中断信号送给CPU。
中断源产生中断信号的时候,会将中断触发器置“1”,表明该中断源产生了中断,要求CPU去响应该中断。
中断触发类型
外部中断申请通过一个物理信号发送到NVIC/GIC,可以是电平触发或边沿触发。
中断向量
中断服务程序的入口地址。
中断向量表
存储中断向量的存储区,中断向量与中断号对应,中断向量在中断向量表中按照中断号顺序存储。
中断共享
当外设较少时,可以实现一个外设对应一个中断号,但为了支持更多的硬件设备,可以让多个设备共享
一个中断号,共享同一个中断号的中断处理程序形成一个链表。当外部设备产生中断申请时,系统会
遍历执行中断号对应的中断处理程序链表直到找到对应设备的中断处理程序。在遍历执行过程中,
各中断处理程序可以通过检测设备ID,判断是否是这个中断处理程序对应的设备产生的中断。
核间中断
对于多核系统,中断控制器允许一个CPU的硬件线程去中断其他CPU的硬件线程,这种方式被称为核间中断。
核间中断的实现基础是多CPU内存共享,采用核间中断可以减少某个CPU负荷过大,有效提升系统效率。
目前只有GIC中断控制器支持。
使用场景
当有中断请求产生时,CPU暂停当前的任务,转而去响应外设请求。根据需要,用户通过
中断申请,注册中断处理程序,可以指定CPU响应中断请求时所执行的具体操作。
开发流程
调用中断创建接口LOS_HwiCreate创建中断。
如果是SMP模式,调用LOS_HwiSetAffinity设置中断的亲和性,否则直接进入步骤4。
调用LOS_HwiEnable接口使能指定中断。
调用LOS_HwiTrigger接口触发指定中断(该接口通过写中断控制器的相关寄存器模拟外部中断,一般的外设设备,不需要执行这一步)。
调用LOS_HwiDisable接口屏蔽指定中断,此接口根据实际情况使用,判断是否需要屏蔽中断。
调用LOS_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。
注意事项
根据具体硬件,配置支持的最大中断数及可设置的中断优先级个数。
中断共享机制,支持不同的设备使用相同的中断号注册同一中断处理程序,但中断处理程序的入参pDevId(设备号)
必须唯一,代表不同的设备。即同一中断号,同一dev只能挂载一次;但同一中断号,同一中断处理程序,dev不同则可以重复挂载。
中断处理程序耗时不能过长,否则会影响CPU对中断的及时响应。
中断响应过程中不能执行引起调度的函数。
中断恢复LOS_IntRestore()的入参必须是与之对应的LOS_IntLock()的返回值(即关中断之前的CPSR值)。
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。
以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。
* @endverbatim
/*!
* @file los_hwi.c
* @brief 硬中断主文件
* @link
* @verbatim
基本概念
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,
这个过程就叫做中断。通过中断机制,可以使CPU避免把大量时间耗费在等待、查询外设状态的操作上,
大大提高系统实时性以及执行效率。
异常处理是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,
例如虚拟内存缺页异常、打印异常发生时函数的调用栈信息、CPU现场信息、任务的堆栈情况等。
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,产生一个中断信号,
该信号连接至中断控制器。中断控制器是一方面接收其它外设中断引脚的输入,另一方面它会发出中断信号给CPU。
可以通过对中断控制器编程来打开和关闭中断源、设置中断源的优先级和触发方式。
常用的中断控制器有VIC(Vector Interrupt Controller)和GIC(General Interrupt Controller)。
在ARM Cortex-A7中使用的中断控制器是GIC。CPU收到中断控制器发送的中断信号后,中断当前任务来响应中断请求。
异常处理就是可以打断CPU正常运行流程的一些事情,如未定义指令异常、试图修改只读的数据异常、不对齐的地址访问异常等。
当异常发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被异常打断的程序。
中断特性:
中断共享,且可配置。
中断嵌套,即高优先级的中断可抢占低优先级的中断,且可配置。
使用独立中断栈,可配置。
可配置支持的中断优先级个数。
可配置支持的中断数。
中断相关的硬件介绍
与中断相关的硬件可以划分为三类:设备、中断控制器、CPU本身。
设备
发起中断的源,当设备需要请求CPU时,产生一个中断信号,该信号连接至中断控制器。
中断控制器
中断控制器是CPU众多外设中的一个,它一方面接收其它外设中断引脚的输入,另一方面,
它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源
的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和
GIC(General Interrupt Controller)。在ARM Cortex-M系列中使用的中断控制器是
NVIC(Nested Vector Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。
CPU
CPU会响应中断源的请求,中断当前正在执行的任务,转而执行中断处理程序。
中断相关概念
中断号
每个中断请求信号都会有特定的标志,使得计算机能够判断是哪个设备提出的中断请求,这个标志就是中断号。
中断请求
“紧急事件”需向CPU提出申请(发一个电脉冲信号),要求中断,及要求CPU暂停当前执行的任务,
转而处理该“紧急事件”,这一申请过程称为中断请求。
中断优先级
为使系统能够及时响应并处理所有中断,系统根据中断时间的重要性和紧迫程度,将中断源分为若干个级别,
称作中断优先级。
中断处理程序
当外设产生中断请求后,CPU暂停当前的任务,转而响应中断申请,即执行中断处理程序。产生中断的每个设备
都有相应的中断处理程序。
中断嵌套
中断嵌套也称为中断抢占,指的是正在执行一个中断处理程序时,如果有另一个优先级更高的中断源提出中断请求,
这时会暂时终止当前正在执行的优先级较低的中断源的中断处理程序,转而去处理更高优先级的中断请求,待处理完毕,
再返回到之前被中断的处理程序中继续执行。
中断触发
中断源向中断控制器发送中断信号,中断控制器对中断进行仲裁,确定优先级,将中断信号送给CPU。
中断源产生中断信号的时候,会将中断触发器置“1”,表明该中断源产生了中断,要求CPU去响应该中断。
中断触发类型
外部中断申请通过一个物理信号发送到NVIC/GIC,可以是电平触发或边沿触发。
中断向量
中断服务程序的入口地址。
中断向量表
存储中断向量的存储区,中断向量与中断号对应,中断向量在中断向量表中按照中断号顺序存储。
中断共享
当外设较少时,可以实现一个外设对应一个中断号,但为了支持更多的硬件设备,可以让多个设备共享
一个中断号,共享同一个中断号的中断处理程序形成一个链表。当外部设备产生中断申请时,系统会
遍历执行中断号对应的中断处理程序链表直到找到对应设备的中断处理程序。在遍历执行过程中,
各中断处理程序可以通过检测设备ID,判断是否是这个中断处理程序对应的设备产生的中断。
核间中断
对于多核系统,中断控制器允许一个CPU的硬件线程去中断其他CPU的硬件线程,这种方式被称为核间中断。
核间中断的实现基础是多CPU内存共享,采用核间中断可以减少某个CPU负荷过大,有效提升系统效率。
目前只有GIC中断控制器支持。
使用场景
当有中断请求产生时,CPU暂停当前的任务,转而去响应外设请求。根据需要,用户通过
中断申请,注册中断处理程序,可以指定CPU响应中断请求时所执行的具体操作。
开发流程
调用中断创建接口LOS_HwiCreate创建中断。
如果是SMP模式,调用LOS_HwiSetAffinity设置中断的亲和性,否则直接进入步骤4。
调用LOS_HwiEnable接口使能指定中断。
调用LOS_HwiTrigger接口触发指定中断(该接口通过写中断控制器的相关寄存器模拟外部中断,一般的外设设备,不需要执行这一步)。
调用LOS_HwiDisable接口屏蔽指定中断,此接口根据实际情况使用,判断是否需要屏蔽中断。
调用LOS_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。
注意事项
根据具体硬件,配置支持的最大中断数及可设置的中断优先级个数。
中断共享机制,支持不同的设备使用相同的中断号注册同一中断处理程序,但中断处理程序的入参pDevId(设备号)
必须唯一,代表不同的设备。即同一中断号,同一dev只能挂载一次;但同一中断号,同一中断处理程序,dev不同则可以重复挂载。
中断处理程序耗时不能过长,否则会影响CPU对中断的及时响应。
中断响应过程中不能执行引起调度的函数。
中断恢复LOS_IntRestore()的入参必须是与之对应的LOS_IntLock()的返回值(即关中断之前的CPSR值)。
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。
以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。
* @endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/44/vector.png
* @version
* @author weharmonyos.com
* @date 2021-11-16
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_hwi.h"
#include "los_memory.h"
#include "los_spinlock.h"
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
#include "los_sched_pri.h"
#include "los_hook.h"
/* spinlock for hwi module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_hwiSpin); ///< 注意全局变量 g_hwiSpin 是在宏里面定义的
#define HWI_LOCK(state) LOS_SpinLockSave(&g_hwiSpin, &(state))
#define HWI_UNLOCK(state) LOS_SpinUnlockRestore(&g_hwiSpin, (state))
size_t g_intCount[LOSCFG_KERNEL_CORE_NUM] = {0};///< 记录每个CPUcore的中断数量
HwiHandleForm g_hwiForm[OS_HWI_MAX_NUM]; ///< 中断注册表 @note_why 用 form 来表示?有种写 HTML的感觉
STATIC CHAR *g_hwiFormName[OS_HWI_MAX_NUM] = {0};///< 记录每个硬中断的名称
STATIC UINT32 g_hwiFormCnt[OS_HWI_MAX_NUM] = {0};///< 记录每个硬中断的总数量
/**
* @brief 增加一个中断数,递增的,所以只有++ ,没有--
*
* @param index
* @return VOID
*/
VOID OsIncHwiFormCnt(UINT32 index)
{
g_hwiFormCnt[index]++;
}
/**
* @brief 获取某个中断的中断次数
*
* @param index
* @return UINT32
*/
UINT32 OsGetHwiFormCnt(UINT32 index)
{
return g_hwiFormCnt[index];
}
CHAR *OsGetHwiFormName(UINT32 index)//获取某个中断的名称
{
return g_hwiFormName[index];
}
/// 获取系统支持的最大中断数
UINT32 LOS_GetSystemHwiMaximum(VOID)
{
return OS_HWI_MAX_NUM;
}
typedef VOID (*HWI_PROC_FUNC0)(VOID);
typedef VOID (*HWI_PROC_FUNC2)(INT32, VOID *);
VOID OsInterrupt(UINT32 intNum)//中断实际处理函数
{
HwiHandleForm *hwiForm = NULL;
UINT32 *intCnt = NULL;
intCnt = &g_intCount[ArchCurrCpuid()];//当前CPU的中断总数量 ++
*intCnt = *intCnt + 1;//@note_why 这里没看明白为什么要 +1
OsSchedIrqStartTime();
#ifdef LOSCFG_CPUP_INCLUDE_IRQ //开启查询系统CPU的占用率的中断
OsCpupIrqStart();//记录本次中断处理开始时间
#endif
OsHookCall(LOS_HOOK_TYPE_ISR_ENTER, intNum);
hwiForm = (&g_hwiForm[intNum]);//获取对应中断的实体
#ifndef LOSCFG_NO_SHARED_IRQ //如果没有定义不共享中断 ,意思就是如果是共享中断
while (hwiForm->pstNext != NULL) { //一直撸到最后
hwiForm = hwiForm->pstNext;//下一个继续撸
#endif
if (hwiForm->uwParam) {//有参数的情况
HWI_PROC_FUNC2 func = (HWI_PROC_FUNC2)hwiForm->pfnHook;//获取回调函数
if (func != NULL) {
UINTPTR *param = (UINTPTR *)(hwiForm->uwParam);
func((INT32)(*param), (VOID *)(*(param + 1)));//运行带参数的回调函数
}
} else {//没有参数的情况
HWI_PROC_FUNC0 func = (HWI_PROC_FUNC0)hwiForm->pfnHook;//获取回调函数
if (func != NULL) {
func();//运行回调函数
}
}
#ifndef LOSCFG_NO_SHARED_IRQ
}
#endif
++g_hwiFormCnt[intNum];//对应中断号计数器总数累加
OsHookCall(LOS_HOOK_TYPE_ISR_EXIT, intNum);
#ifdef LOSCFG_CPUP_INCLUDE_IRQ
OsCpupIrqEnd(intNum);
#endif
OsSchedIrqUpdateUsedTime();
/* Must keep the operation at the end of the interface */
*intCnt = *intCnt - 1;
}
///申请内核空间拷贝硬中断参数
STATIC HWI_ARG_T OsHwiCpIrqParam(const HwiIrqParam *irqParam)
{
HwiIrqParam *paramByAlloc = NULL;
if (irqParam != NULL) {
paramByAlloc = (HwiIrqParam *)LOS_MemAlloc(m_aucSysMem0, sizeof(HwiIrqParam));
if (paramByAlloc == NULL) {
return LOS_NOK;
}
(VOID)memcpy_s(paramByAlloc, sizeof(HwiIrqParam), irqParam, sizeof(HwiIrqParam));
}
/* When "irqParam" is NULL, the function return 0(LOS_OK). */
return (HWI_ARG_T)paramByAlloc;
}
#ifdef LOSCFG_NO_SHARED_IRQ
STATIC UINT32 OsHwiDelNoShared(HWI_HANDLE_T hwiNum)
{
UINT32 intSave;
HWI_LOCK(intSave);//申请硬中断自旋锁
g_hwiForm[hwiNum].pfnHook = NULL;//回调函数直接NULL
if (g_hwiForm[hwiNum].uwParam) {//如有参数
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)g_hwiForm[hwiNum].uwParam);//释放内存
}
g_hwiForm[hwiNum].uwParam = 0; //NULL
HWI_UNLOCK(intSave);//释放硬中断自旋锁
return LOS_OK;
}
///创建一个不支持共享的中断
STATIC UINT32 OsHwiCreateNoShared(HWI_HANDLE_T hwiNum, HWI_MODE_T hwiMode,
HWI_PROC_FUNC hwiHandler, const HwiIrqParam *irqParam)
{
HWI_ARG_T retParam;
UINT32 intSave;
HWI_LOCK(intSave);
if (g_hwiForm[hwiNum].pfnHook == NULL) {
g_hwiForm[hwiNum].pfnHook = hwiHandler;//记录上回调函数
retParam = OsHwiCpIrqParam(irqParam);//获取中断处理函数的参数
if (retParam == LOS_NOK) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_NO_MEMORY;
}
g_hwiForm[hwiNum].uwParam = retParam;//作为硬中断处理函数的参数
} else {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_ALREADY_CREATED;
}
HWI_UNLOCK(intSave);
return LOS_OK;
}
#else //删除一个共享中断
STATIC UINT32 OsHwiDelShared(HWI_HANDLE_T hwiNum, const HwiIrqParam *irqParam)
{
HwiHandleForm *hwiForm = NULL;
HwiHandleForm *hwiFormtmp = NULL;
UINT32 hwiValid = FALSE;
UINT32 intSave;
HWI_LOCK(intSave);
hwiForm = &g_hwiForm[hwiNum];//从全局注册的中断向量表中获取中断项
hwiFormtmp = hwiForm;
if ((hwiForm->uwParam & IRQF_SHARED) && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_SHARED_ERROR;
}
if ((hwiForm->pstNext != NULL) && !(hwiForm->uwParam & IRQF_SHARED)) {
hwiForm = hwiForm->pstNext;
if (hwiForm->uwParam) {
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)hwiForm->uwParam);
}
(VOID)LOS_MemFree(m_aucSysMem0, hwiForm);
hwiFormtmp->pstNext = NULL;
g_hwiFormName[hwiNum] = NULL;
HWI_UNLOCK(intSave);
return LOS_OK;
}
hwiForm = hwiForm->pstNext;
while (hwiForm != NULL) {
if (((HwiIrqParam *)(hwiForm->uwParam))->pDevId != irqParam->pDevId) {
hwiFormtmp = hwiForm;
hwiForm = hwiForm->pstNext;
} else {
hwiFormtmp->pstNext = hwiForm->pstNext;
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)hwiForm->uwParam);
(VOID)LOS_MemFree(m_aucSysMem0, hwiForm);
hwiValid = TRUE;
break;
}
}
if (hwiValid != TRUE) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_HWINUM_UNCREATE;
}
if (g_hwiForm[hwiNum].pstNext == NULL) {
g_hwiForm[hwiNum].uwParam = 0;
g_hwiFormName[hwiNum] = NULL;
}
HWI_UNLOCK(intSave);
return LOS_OK;
}
///创建一个共享硬件中断,共享中断就是一个中断能触发多个响应函数
STATIC UINT32 OsHwiCreateShared(HWI_HANDLE_T hwiNum, HWI_MODE_T hwiMode,
HWI_PROC_FUNC hwiHandler, const HwiIrqParam *irqParam)
{
UINT32 intSave;
HwiHandleForm *hwiFormNode = NULL;
HwiHandleForm *hwiForm = NULL;
HwiIrqParam *hwiParam = NULL;
HWI_MODE_T modeResult = hwiMode & IRQF_SHARED;
if (modeResult && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {
return OS_ERRNO_HWI_SHARED_ERROR;
}
HWI_LOCK(intSave);//中断自旋锁
hwiForm = &g_hwiForm[hwiNum];//获取中断处理项
if ((hwiForm->pstNext != NULL) && ((modeResult == 0) || (!(hwiForm->uwParam & IRQF_SHARED)))) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_SHARED_ERROR;
}
while (hwiForm->pstNext != NULL) {//pstNext指向 共享中断的各处理函数节点,此处一直撸到最后一个
hwiForm = hwiForm->pstNext;//找下一个中断
hwiParam = (HwiIrqParam *)(hwiForm->uwParam);//获取中断参数,用于检测该设备ID是否已经有中断处理函数
if (hwiParam->pDevId == irqParam->pDevId) {//设备ID一致时,说明设备对应的中断处理函数已经存在了.
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_ALREADY_CREATED;
}
}
hwiFormNode = (HwiHandleForm *)LOS_MemAlloc(m_aucSysMem0, sizeof(HwiHandleForm));//创建一个中断处理节点
if (hwiFormNode == NULL) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_NO_MEMORY;
}
hwiFormNode->uwParam = OsHwiCpIrqParam(irqParam);//获取中断处理函数的参数
if (hwiFormNode->uwParam == LOS_NOK) {
HWI_UNLOCK(intSave);
(VOID)LOS_MemFree(m_aucSysMem0, hwiFormNode);
return OS_ERRNO_HWI_NO_MEMORY;
}
hwiFormNode->pfnHook = hwiHandler;//绑定中断处理函数
hwiFormNode->pstNext = (struct tagHwiHandleForm *)NULL;//指定下一个中断为NULL,用于后续遍历找到最后一个中断项(见于以上 while (hwiForm->pstNext != NULL)处)
hwiForm->pstNext = hwiFormNode;//共享中断
if ((irqParam != NULL) && (irqParam->pName != NULL)) {
g_hwiFormName[hwiNum] = (CHAR *)irqParam->pName;
}
g_hwiForm[hwiNum].uwParam = modeResult;
HWI_UNLOCK(intSave);
return LOS_OK;
}
#endif
/*
* Description : initialization of the hardware interrupt
*/
LITE_OS_SEC_TEXT_INIT VOID OsHwiInit(VOID)//硬件中断初始化
{
UINT32 hwiNum;
for (hwiNum = 0; hwiNum < OS_HWI_MAX_NUM; hwiNum++) {//初始化中断向量表,默认128个中断
g_hwiForm[hwiNum].pfnHook = NULL;
g_hwiForm[hwiNum].uwParam = 0;
g_hwiForm[hwiNum].pstNext = NULL;
}
(VOID)memset_s(g_hwiFormName, (sizeof(CHAR *) * OS_HWI_MAX_NUM), 0, (sizeof(CHAR *) * OS_HWI_MAX_NUM));
HalIrqInit();
return;
}
/**
* @brief 创建一个硬中断
\n 中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,
\n handleIrq会调用该中断处理程序
* @param hwiNum 硬中断句柄编号 默认范围[0-127]
* @param hwiPrio 硬中断优先级
* @param hwiMode 硬中断模式 共享和非共享
* @param hwiHandler 硬中断处理函数
* @param irqParam 硬中断处理函数参数
* @return LITE_OS_SEC_TEXT_INIT
*/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum,
HWI_PRIOR_T hwiPrio,
HWI_MODE_T hwiMode,
HWI_PROC_FUNC hwiHandler,
HwiIrqParam *irqParam)
{
UINT32 ret;
(VOID)hwiPrio;
if (hwiHandler == NULL) {//中断处理函数不能为NULL
return OS_ERRNO_HWI_PROC_FUNC_NULL;
}
if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {//中断数区间限制 [32,96]
return OS_ERRNO_HWI_NUM_INVALID;
}
#ifdef LOSCFG_NO_SHARED_IRQ //不支持共享中断
ret = OsHwiCreateNoShared(hwiNum, hwiMode, hwiHandler, irqParam);
#else
ret = OsHwiCreateShared(hwiNum, hwiMode, hwiHandler, irqParam);
#endif
return ret;
}
///删除一个硬中断
LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiDelete(HWI_HANDLE_T hwiNum, HwiIrqParam *irqParam)
{
UINT32 ret;
if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {
return OS_ERRNO_HWI_NUM_INVALID;
}
#ifdef LOSCFG_NO_SHARED_IRQ //不支持共享中断
ret = OsHwiDelNoShared(hwiNum);
#else
ret = OsHwiDelShared(hwiNum, irqParam);
#endif
return ret;
}
* @version
* @author weharmonyos.com
* @date 2021-11-16
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_hwi.h"
#include "los_memory.h"
#include "los_spinlock.h"
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
#include "los_sched_pri.h"
#include "los_hook.h"
/* spinlock for hwi module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_hwiSpin); ///< 注意全局变量 g_hwiSpin 是在宏里面定义的
#define HWI_LOCK(state) LOS_SpinLockSave(&g_hwiSpin, &(state))
#define HWI_UNLOCK(state) LOS_SpinUnlockRestore(&g_hwiSpin, (state))
size_t g_intCount[LOSCFG_KERNEL_CORE_NUM] = {0};///< 记录每个CPUcore的中断数量
HwiHandleForm g_hwiForm[OS_HWI_MAX_NUM]; ///< 中断注册表 @note_why 用 form 来表示?有种写 HTML的感觉
STATIC CHAR *g_hwiFormName[OS_HWI_MAX_NUM] = {0};///< 记录每个硬中断的名称
STATIC UINT32 g_hwiFormCnt[OS_HWI_MAX_NUM] = {0};///< 记录每个硬中断的总数量
/**
* @brief 增加一个中断数,递增的,所以只有++ ,没有--
*
* @param index
* @return VOID
*/
VOID OsIncHwiFormCnt(UINT32 index)
{
g_hwiFormCnt[index]++;
}
/**
* @brief 获取某个中断的中断次数
*
* @param index
* @return UINT32
*/
UINT32 OsGetHwiFormCnt(UINT32 index)
{
return g_hwiFormCnt[index];
}
CHAR *OsGetHwiFormName(UINT32 index)//获取某个中断的名称
{
return g_hwiFormName[index];
}
/// 获取系统支持的最大中断数
UINT32 LOS_GetSystemHwiMaximum(VOID)
{
return OS_HWI_MAX_NUM;
}
typedef VOID (*HWI_PROC_FUNC0)(VOID);
typedef VOID (*HWI_PROC_FUNC2)(INT32, VOID *);
VOID OsInterrupt(UINT32 intNum)//中断实际处理函数
{
HwiHandleForm *hwiForm = NULL;
UINT32 *intCnt = NULL;
intCnt = &g_intCount[ArchCurrCpuid()];//当前CPU的中断总数量 ++
*intCnt = *intCnt + 1;//@note_why 这里没看明白为什么要 +1
OsSchedIrqStartTime();
#ifdef LOSCFG_CPUP_INCLUDE_IRQ //开启查询系统CPU的占用率的中断
OsCpupIrqStart();//记录本次中断处理开始时间
#endif
OsHookCall(LOS_HOOK_TYPE_ISR_ENTER, intNum);
hwiForm = (&g_hwiForm[intNum]);//获取对应中断的实体
#ifndef LOSCFG_NO_SHARED_IRQ //如果没有定义不共享中断 ,意思就是如果是共享中断
while (hwiForm->pstNext != NULL) { //一直撸到最后
hwiForm = hwiForm->pstNext;//下一个继续撸
#endif
if (hwiForm->uwParam) {//有参数的情况
HWI_PROC_FUNC2 func = (HWI_PROC_FUNC2)hwiForm->pfnHook;//获取回调函数
if (func != NULL) {
UINTPTR *param = (UINTPTR *)(hwiForm->uwParam);
func((INT32)(*param), (VOID *)(*(param + 1)));//运行带参数的回调函数
}
} else {//没有参数的情况
HWI_PROC_FUNC0 func = (HWI_PROC_FUNC0)hwiForm->pfnHook;//获取回调函数
if (func != NULL) {
func();//运行回调函数
}
}
#ifndef LOSCFG_NO_SHARED_IRQ
}
#endif
++g_hwiFormCnt[intNum];//对应中断号计数器总数累加
OsHookCall(LOS_HOOK_TYPE_ISR_EXIT, intNum);
#ifdef LOSCFG_CPUP_INCLUDE_IRQ
OsCpupIrqEnd(intNum);
#endif
OsSchedIrqUpdateUsedTime();
/* Must keep the operation at the end of the interface */
*intCnt = *intCnt - 1;
}
///申请内核空间拷贝硬中断参数
STATIC HWI_ARG_T OsHwiCpIrqParam(const HwiIrqParam *irqParam)
{
HwiIrqParam *paramByAlloc = NULL;
if (irqParam != NULL) {
paramByAlloc = (HwiIrqParam *)LOS_MemAlloc(m_aucSysMem0, sizeof(HwiIrqParam));
if (paramByAlloc == NULL) {
return LOS_NOK;
}
(VOID)memcpy_s(paramByAlloc, sizeof(HwiIrqParam), irqParam, sizeof(HwiIrqParam));
}
/* When "irqParam" is NULL, the function return 0(LOS_OK). */
return (HWI_ARG_T)paramByAlloc;
}
#ifdef LOSCFG_NO_SHARED_IRQ
STATIC UINT32 OsHwiDelNoShared(HWI_HANDLE_T hwiNum)
{
UINT32 intSave;
HWI_LOCK(intSave);//申请硬中断自旋锁
g_hwiForm[hwiNum].pfnHook = NULL;//回调函数直接NULL
if (g_hwiForm[hwiNum].uwParam) {//如有参数
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)g_hwiForm[hwiNum].uwParam);//释放内存
}
g_hwiForm[hwiNum].uwParam = 0; //NULL
HWI_UNLOCK(intSave);//释放硬中断自旋锁
return LOS_OK;
}
///创建一个不支持共享的中断
STATIC UINT32 OsHwiCreateNoShared(HWI_HANDLE_T hwiNum, HWI_MODE_T hwiMode,
HWI_PROC_FUNC hwiHandler, const HwiIrqParam *irqParam)
{
HWI_ARG_T retParam;
UINT32 intSave;
HWI_LOCK(intSave);
if (g_hwiForm[hwiNum].pfnHook == NULL) {
g_hwiForm[hwiNum].pfnHook = hwiHandler;//记录上回调函数
retParam = OsHwiCpIrqParam(irqParam);//获取中断处理函数的参数
if (retParam == LOS_NOK) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_NO_MEMORY;
}
g_hwiForm[hwiNum].uwParam = retParam;//作为硬中断处理函数的参数
} else {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_ALREADY_CREATED;
}
HWI_UNLOCK(intSave);
return LOS_OK;
}
#else //删除一个共享中断
STATIC UINT32 OsHwiDelShared(HWI_HANDLE_T hwiNum, const HwiIrqParam *irqParam)
{
HwiHandleForm *hwiForm = NULL;
HwiHandleForm *hwiFormtmp = NULL;
UINT32 hwiValid = FALSE;
UINT32 intSave;
HWI_LOCK(intSave);
hwiForm = &g_hwiForm[hwiNum];//从全局注册的中断向量表中获取中断项
hwiFormtmp = hwiForm;
if ((hwiForm->uwParam & IRQF_SHARED) && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_SHARED_ERROR;
}
if ((hwiForm->pstNext != NULL) && !(hwiForm->uwParam & IRQF_SHARED)) {
hwiForm = hwiForm->pstNext;
if (hwiForm->uwParam) {
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)hwiForm->uwParam);
}
(VOID)LOS_MemFree(m_aucSysMem0, hwiForm);
hwiFormtmp->pstNext = NULL;
g_hwiFormName[hwiNum] = NULL;
HWI_UNLOCK(intSave);
return LOS_OK;
}
hwiForm = hwiForm->pstNext;
while (hwiForm != NULL) {
if (((HwiIrqParam *)(hwiForm->uwParam))->pDevId != irqParam->pDevId) {
hwiFormtmp = hwiForm;
hwiForm = hwiForm->pstNext;
} else {
hwiFormtmp->pstNext = hwiForm->pstNext;
(VOID)LOS_MemFree(m_aucSysMem0, (VOID *)hwiForm->uwParam);
(VOID)LOS_MemFree(m_aucSysMem0, hwiForm);
hwiValid = TRUE;
break;
}
}
if (hwiValid != TRUE) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_HWINUM_UNCREATE;
}
if (g_hwiForm[hwiNum].pstNext == NULL) {
g_hwiForm[hwiNum].uwParam = 0;
g_hwiFormName[hwiNum] = NULL;
}
HWI_UNLOCK(intSave);
return LOS_OK;
}
///创建一个共享硬件中断,共享中断就是一个中断能触发多个响应函数
STATIC UINT32 OsHwiCreateShared(HWI_HANDLE_T hwiNum, HWI_MODE_T hwiMode,
HWI_PROC_FUNC hwiHandler, const HwiIrqParam *irqParam)
{
UINT32 intSave;
HwiHandleForm *hwiFormNode = NULL;
HwiHandleForm *hwiForm = NULL;
HwiIrqParam *hwiParam = NULL;
HWI_MODE_T modeResult = hwiMode & IRQF_SHARED;
if (modeResult && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {
return OS_ERRNO_HWI_SHARED_ERROR;
}
HWI_LOCK(intSave);//中断自旋锁
hwiForm = &g_hwiForm[hwiNum];//获取中断处理项
if ((hwiForm->pstNext != NULL) && ((modeResult == 0) || (!(hwiForm->uwParam & IRQF_SHARED)))) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_SHARED_ERROR;
}
while (hwiForm->pstNext != NULL) {//pstNext指向 共享中断的各处理函数节点,此处一直撸到最后一个
hwiForm = hwiForm->pstNext;//找下一个中断
hwiParam = (HwiIrqParam *)(hwiForm->uwParam);//获取中断参数,用于检测该设备ID是否已经有中断处理函数
if (hwiParam->pDevId == irqParam->pDevId) {//设备ID一致时,说明设备对应的中断处理函数已经存在了.
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_ALREADY_CREATED;
}
}
hwiFormNode = (HwiHandleForm *)LOS_MemAlloc(m_aucSysMem0, sizeof(HwiHandleForm));//创建一个中断处理节点
if (hwiFormNode == NULL) {
HWI_UNLOCK(intSave);
return OS_ERRNO_HWI_NO_MEMORY;
}
hwiFormNode->uwParam = OsHwiCpIrqParam(irqParam);//获取中断处理函数的参数
if (hwiFormNode->uwParam == LOS_NOK) {
HWI_UNLOCK(intSave);
(VOID)LOS_MemFree(m_aucSysMem0, hwiFormNode);
return OS_ERRNO_HWI_NO_MEMORY;
}
hwiFormNode->pfnHook = hwiHandler;//绑定中断处理函数
hwiFormNode->pstNext = (struct tagHwiHandleForm *)NULL;//指定下一个中断为NULL,用于后续遍历找到最后一个中断项(见于以上 while (hwiForm->pstNext != NULL)处)
hwiForm->pstNext = hwiFormNode;//共享中断
if ((irqParam != NULL) && (irqParam->pName != NULL)) {
g_hwiFormName[hwiNum] = (CHAR *)irqParam->pName;
}
g_hwiForm[hwiNum].uwParam = modeResult;
HWI_UNLOCK(intSave);
return LOS_OK;
}
#endif
/*
* Description : initialization of the hardware interrupt
*/
LITE_OS_SEC_TEXT_INIT VOID OsHwiInit(VOID)//硬件中断初始化
{
UINT32 hwiNum;
for (hwiNum = 0; hwiNum < OS_HWI_MAX_NUM; hwiNum++) {//初始化中断向量表,默认128个中断
g_hwiForm[hwiNum].pfnHook = NULL;
g_hwiForm[hwiNum].uwParam = 0;
g_hwiForm[hwiNum].pstNext = NULL;
}
(VOID)memset_s(g_hwiFormName, (sizeof(CHAR *) * OS_HWI_MAX_NUM), 0, (sizeof(CHAR *) * OS_HWI_MAX_NUM));
HalIrqInit();
return;
}
/**
* @brief 创建一个硬中断
\n 中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,
\n handleIrq会调用该中断处理程序
* @param hwiNum 硬中断句柄编号 默认范围[0-127]
* @param hwiPrio 硬中断优先级
* @param hwiMode 硬中断模式 共享和非共享
* @param hwiHandler 硬中断处理函数
* @param irqParam 硬中断处理函数参数
* @return LITE_OS_SEC_TEXT_INIT
*/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum,
HWI_PRIOR_T hwiPrio,
HWI_MODE_T hwiMode,
HWI_PROC_FUNC hwiHandler,
HwiIrqParam *irqParam)
{
UINT32 ret;
(VOID)hwiPrio;
if (hwiHandler == NULL) {//中断处理函数不能为NULL
return OS_ERRNO_HWI_PROC_FUNC_NULL;
}
if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {//中断数区间限制 [32,96]
return OS_ERRNO_HWI_NUM_INVALID;
}
#ifdef LOSCFG_NO_SHARED_IRQ //不支持共享中断
ret = OsHwiCreateNoShared(hwiNum, hwiMode, hwiHandler, irqParam);
#else
ret = OsHwiCreateShared(hwiNum, hwiMode, hwiHandler, irqParam);
#endif
return ret;
}
///删除一个硬中断
LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiDelete(HWI_HANDLE_T hwiNum, HwiIrqParam *irqParam)
{
UINT32 ret;
if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {
return OS_ERRNO_HWI_NUM_INVALID;
}
#ifdef LOSCFG_NO_SHARED_IRQ //不支持共享中断
ret = OsHwiDelNoShared(hwiNum);
#else
ret = OsHwiDelShared(hwiNum, irqParam);
#endif
return ret;
}
......@@ -323,15 +323,15 @@ STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)
#define LOS_SCHED_NORMAL 0U ///< 正常调度
#define LOS_SCHED_FIFO 1U ///< 先进先出,按顺序
#define LOS_SCHED_RR 2U ///< 抢占式调度
#define LOS_SCHED_IDLE 3U
#define LOS_SCHED_RR 2U ///< 抢占式调度,鸿蒙默认调度方式
#define LOS_SCHED_IDLE 3U ///< 空闲不调度
#define LOS_PRIO_PROCESS 0U ///< 进程标识
#define LOS_PRIO_PGRP 1U ///< 进程组标识
#define LOS_PRIO_USER 2U ///< 用户标识
#define OS_USER_PRIVILEGE_PROCESS_GROUP 1U
#define OS_KERNEL_PROCESS_GROUP 2U
#define OS_USER_PRIVILEGE_PROCESS_GROUP 1U ///< 用户态进程组ID
#define OS_KERNEL_PROCESS_GROUP 2U ///< 内核态进程组ID
/*
* Process exit code
......
......@@ -59,10 +59,10 @@ extern "C" {
*
* Task siginal types.
*/
#define SIGNAL_NONE 0U //无信号
#define SIGNAL_KILL (1U << 0) //干掉
#define SIGNAL_SUSPEND (1U << 1) //挂起
#define SIGNAL_AFFI (1U << 2) //CPU 亲和性,一个任务被切换后被同一个CPU再次执行,则亲和力高
#define SIGNAL_NONE 0U ///< 无信号
#define SIGNAL_KILL (1U << 0) ///< 干掉
#define SIGNAL_SUSPEND (1U << 1) ///< 挂起
#define SIGNAL_AFFI (1U << 2) ///< CPU 亲和性,一个任务被切换后被同一个CPU再次执行,则亲和力高
/* scheduler lock */
extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
......@@ -286,8 +286,8 @@ extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
* @par Dependency:
* <ul><li>los_task_pri.h: the header file that contains the API declaration.</li></ul>
* @see
*/ ///通过任务ID找到任务实体
#define OS_TCB_FROM_TID(taskID) (((LosTaskCB *)g_taskCBArray) + (taskID))
*/
#define OS_TCB_FROM_TID(taskID) (((LosTaskCB *)g_taskCBArray) + (taskID)) ///< 通过任务ID从任务池中拿到实体
#ifndef LOSCFG_STACK_POINT_ALIGN_SIZE
#define LOSCFG_STACK_POINT_ALIGN_SIZE (sizeof(UINTPTR) * 2)
......@@ -304,7 +304,7 @@ typedef struct {
VOID *stackPointer; /**< Task stack pointer | 内核栈指针位置(SP) */
UINT16 taskStatus; /**< Task status | 各种状态标签,可以拥有多种标签,按位标识 */
UINT16 priority; /**< Task priority | 任务优先级[0:31],默认是31级 */
UINT16 policy; ///< 任务的调度方式(三种 .. LOS_SCHED_RR )
UINT16 policy; ///< 任务的调度方式(三种 .. LOS_SCHED_RR LOS_SCHED_FIFO .. )
UINT64 startTime; /**< The start time of each phase of task | 任务开始时间 */
UINT64 irqStartTime; /**< Interrupt start time | 任务中断开始时间 */
UINT32 irqUsedTime; /**< Interrupt consumption time | 任务中断恢复时间 */
......@@ -337,8 +337,8 @@ typedef struct {
UINT16 currCpu; /**< CPU core number of this task is running on | 正在运行此任务的CPU内核号 */
UINT16 lastCpu; /**< CPU core number of this task is running on last time | 上次运行此任务的CPU内核号 */
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores | CPU亲和力掩码,最多支持16核,亲和力很重要,多核情况下尽量一个任务在一个CPU核上运行,提高效率 */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
UINT32 syncSignal; /**< Synchronization for signal handling | 用于CPU之间 同步信号 */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC //多核情况下的任务同步开关,采用信号量实现
UINT32 syncSignal; /**< Synchronization for signal handling | 用于CPU之间同步信号量 */
#endif
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP //SMP死锁检测开关
LockDep lockDep; ///< 死锁依赖检测
......@@ -357,8 +357,8 @@ typedef struct {
UINTPTR waitID; /**< Wait for the PID or GID of the child process | */
UINT16 waitFlag; /**< The type of child process that is waiting, belonging to a group or parent,
a specific child process, or any child process | 以什么样的方式等待子进程结束(OS_TASK_WAIT_PROCESS | OS_TASK_WAIT_GID | ..) */
#ifdef LOSCFG_KERNEL_LITEIPC
IpcTaskInfo *ipcTaskInfo; ///< 任务IPC信息结构体
#ifdef LOSCFG_KERNEL_LITEIPC //轻量级进程间通信开关
IpcTaskInfo *ipcTaskInfo; ///< 任务间通讯信息结构体
#endif
#ifdef LOSCFG_KERNEL_PERF
UINTPTR pc; ///< pc寄存器
......@@ -380,7 +380,7 @@ struct ProcessSignalInfo {
LosTaskCB *receivedTcb; /**< This TCB received the signal | 如果没有屏蔽信号,任务将接收这个信号. */
};
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);//回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);///< 回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
/**
* @ingroup los_task
......@@ -476,19 +476,19 @@ STATIC INLINE BOOL OsTaskIsKilled(const LosTaskCB *taskCB)
/* get task info */
#define OS_ALL_TASK_MASK 0xFFFFFFFF
#define OS_TASK_WAIT_ANYPROCESS (1 << 0U) ///< 任务等待任何进程出现
#define OS_TASK_WAIT_PROCESS (1 << 1U) ///< 任务等待进程出现
#define OS_TASK_WAIT_GID (1 << 2U) ///< 任务等待组ID
#define OS_TASK_WAIT_SEM (OS_TASK_WAIT_GID + 1) ///< 任务等待信号量发生
#define OS_TASK_WAIT_QUEUE (OS_TASK_WAIT_SEM + 1) ///< 任务等待队列到来
#define OS_TASK_WAIT_JOIN (OS_TASK_WAIT_QUEUE + 1) ///< 任务等待
#define OS_TASK_WAIT_SIGNAL (OS_TASK_WAIT_JOIN + 1) ///< 任务等待信号的到来
#define OS_TASK_WAIT_LITEIPC (OS_TASK_WAIT_SIGNAL + 1) ///< 任务等待liteipc到来
#define OS_TASK_WAIT_MUTEX (OS_TASK_WAIT_LITEIPC + 1) ///< 任务等待MUTEX到来
#define OS_TASK_WAIT_FUTEX (OS_TASK_WAIT_MUTEX + 1) ///< 任务等待FUTEX到来
#define OS_TASK_WAIT_EVENT (OS_TASK_WAIT_FUTEX + 1) ///< 任务等待事件发生
#define OS_TASK_WAIT_COMPLETE (OS_TASK_WAIT_EVENT + 1) ///< 任务等待完成
/// 任务的信号列表
#define OS_TASK_WAIT_ANYPROCESS (1 << 0U) ///< 等待任意进程出现
#define OS_TASK_WAIT_PROCESS (1 << 1U) ///< 等待指定进程出现
#define OS_TASK_WAIT_GID (1 << 2U) ///< 等待组ID
#define OS_TASK_WAIT_SEM (OS_TASK_WAIT_GID + 1) ///< 等待信号量发生
#define OS_TASK_WAIT_QUEUE (OS_TASK_WAIT_SEM + 1) ///< 等待队列到来
#define OS_TASK_WAIT_JOIN (OS_TASK_WAIT_QUEUE + 1) ///< 等待
#define OS_TASK_WAIT_SIGNAL (OS_TASK_WAIT_JOIN + 1) ///<
#define OS_TASK_WAIT_LITEIPC (OS_TASK_WAIT_SIGNAL + 1) ///< 等待liteipc到来
#define OS_TASK_WAIT_MUTEX (OS_TASK_WAIT_LITEIPC + 1) ///< 等待MUTEX到来
#define OS_TASK_WAIT_FUTEX (OS_TASK_WAIT_MUTEX + 1) ///< 等待FUTEX到来
#define OS_TASK_WAIT_EVENT (OS_TASK_WAIT_FUTEX + 1) ///< 等待事件发生
#define OS_TASK_WAIT_COMPLETE (OS_TASK_WAIT_EVENT + 1) ///< 等待结束信号
/// 设置事件阻塞掩码,即设置任务的等待事件.
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
......
......@@ -172,7 +172,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadCheck(const PEVENT_CB_S eventCB, UINT3
}
return LOS_OK;
}
///读取指定事件类型的实现函数,超时时间为相对时间:单位为Tick
/// 读取指定事件类型的实现函数,超时时间为相对时间:单位为Tick
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
UINT32 timeout, BOOL once)
{
......@@ -196,8 +196,8 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventM
runTask->eventMask = eventMask; //等待事件
runTask->eventMode = mode; //事件模式
runTask->taskEvent = eventCB; //事件控制块
OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);
ret = OsSchedTaskWait(&eventCB->stEventList, timeout, TRUE);
OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);//任务进入等待状态,等待事件的到来并设置时长和掩码
ret = OsSchedTaskWait(&eventCB->stEventList, timeout, TRUE);//任务暂停,切换调度.
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
return LOS_ERRNO_EVENT_READ_TIMEOUT;
}
......
......@@ -139,14 +139,14 @@ STATIC INLINE VOID OsSigWaitTaskWake(LosTaskCB *taskCB, INT32 signo)
OsSigEmptySet(&sigcb->sigwaitmask);
}
}
///< 唤醒被挂起的处于等待指定信号的任务
STATIC UINT32 OsPendingTaskWake(LosTaskCB *taskCB, INT32 signo)
{
if (!OsTaskIsPending(taskCB) || !OsProcessIsUserMode(OS_PCB_FROM_PID(taskCB->processID))) {
return 0;
}
if ((signo != SIGKILL) && (taskCB->waitFlag != OS_TASK_WAIT_SIGNAL)) {
if ((signo != SIGKILL) && (taskCB->waitFlag != OS_TASK_WAIT_SIGNAL)) { // @note_thinking 这个判断会不会有问题 ?
return 0;
}
......@@ -760,7 +760,7 @@ VOID *OsSaveSignalContext(VOID *sp, VOID *newSp)
OsProcessExitCodeSignalSet(process, signo);
sigcb->sigContext = sp;
OsInitSignalContext(sp, newSp, sigHandler, signo, sigVal);
OsInitSignalContext(sp, newSp, sigHandler, signo, sigVal);//初始化信号上下文
/* sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
sigcb->sigFlag ^= 1ULL << (signo - 1);
......
/*!
* @file hm_liteipc.c
* @brief 轻量级进程间通信
* @link LiteIPC http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-bundles-ipc.html @endlink
@verbatim
基本概念
LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,
不同于传统的System V IPC机制,LiteIPC主要是为RPC(Remote Procedure Call,即远程过程调用)而设计的,
而且是通过设备文件的方式对上层提供接口的,而非传统的API函数方式。
LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service。整个系统只能有一个ServiceManager,
而Service可以有多个。ServiceManager有两个主要功能:一是负责Service的注册和注销,二是负责管理Service的
访问权限(只有有权限的任务(Task)可以向对应的Service发送IPC消息)。
运行机制
首先将需要接收IPC消息的任务通过ServiceManager注册成为一个Service,然后通过ServiceManager为该Service
任务配置访问权限,即指定哪些任务可以向该Service任务发送IPC消息。LiteIPC的核心思想就是在内核态为
每个Service任务维护一个IPC消息队列,该消息队列通过LiteIPC设备文件向上层用户态程序分别提供代表收取
IPC消息的读操作和代表发送IPC消息的写操作。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -46,33 +70,33 @@
#include "los_vm_phys.h"
#include "los_hook.h"
#define USE_TASKID_AS_HANDLE YES //使用任务ID作为句柄
#define USE_TASKID_AS_HANDLE YES ///< 使用任务ID作为句柄
#define USE_MMAP YES //
#define IPC_IO_DATA_MAX 8192UL //最大的消息内容 8K ,posix最大消息内容 64个字节
#define IPC_IO_DATA_MAX 8192UL ///< 最大的消息内容 8K ,posix最大消息内容 64个字节
#define IPC_MSG_DATA_SZ_MAX (IPC_IO_DATA_MAX * sizeof(SpecialObj) / (sizeof(SpecialObj) + sizeof(size_t)))
#define IPC_MSG_OBJECT_NUM_MAX (IPC_MSG_DATA_SZ_MAX / sizeof(SpecialObj))
#define IPC_MSG_OBJECT_NUM_MAX (IPC_MSG_DATA_SZ_MAX / sizeof(SpecialObj))
#define LITE_IPC_POOL_NAME "liteipc" //ipc池名称
#define LITE_IPC_POOL_NAME "liteipc" ///< ipc池名称
#define LITE_IPC_POOL_PAGE_MAX_NUM 64 /* 256KB */
#define LITE_IPC_POOL_PAGE_DEFAULT_NUM 16 /* 64KB */
#define LITE_IPC_POOL_MAX_SIZE (LITE_IPC_POOL_PAGE_MAX_NUM << PAGE_SHIFT) //最大IPC池 256K
#define LITE_IPC_POOL_DEFAULT_SIZE (LITE_IPC_POOL_PAGE_DEFAULT_NUM << PAGE_SHIFT)//默认IPC池 64K
#define LITE_IPC_POOL_MAX_SIZE (LITE_IPC_POOL_PAGE_MAX_NUM << PAGE_SHIFT) ///< 最大IPC池 256K
#define LITE_IPC_POOL_DEFAULT_SIZE (LITE_IPC_POOL_PAGE_DEFAULT_NUM << PAGE_SHIFT)///< 默认IPC池 64K
#define LITE_IPC_POOL_UVADDR 0x10000000
#define INVAILD_ID (-1)
#define LITEIPC_TIMEOUT_MS 5000UL //超时时间单位毫秒
#define LITEIPC_TIMEOUT_NS 5000000000ULL //超时时间单位纳秒
#define LITEIPC_TIMEOUT_MS 5000UL ///< 超时时间单位毫秒
#define LITEIPC_TIMEOUT_NS 5000000000ULL ///< 超时时间单位纳秒
typedef struct {//IPC使用节点
LOS_DL_LIST list;//通过它挂到对应g_ipcUsedNodelist[processID]上
LOS_DL_LIST list;///< 通过它挂到对应g_ipcUsedNodelist[processID]上
VOID *ptr;
} IpcUsedNode;
STATIC LosMux g_serviceHandleMapMux;
#if (USE_TASKID_AS_HANDLE == YES)// @note_why 前缀cms是何意思? 猜测是Content Management System(内容管理系统)
#if (USE_TASKID_AS_HANDLE == YES) // @note_why 前缀cms是何意思? 猜测是Content Management System(内容管理系统) :(
STATIC HandleInfo g_cmsTask;
#else
STATIC HandleInfo g_serviceHandleMap[MAX_SERVICE_NUM];
STATIC HandleInfo g_serviceHandleMap[MAX_SERVICE_NUM]; ///< 整个系统只能有一个 ServiceManager 用于管理 service
#endif
STATIC LOS_DL_LIST g_ipcPendlist;//阻塞链表,上面挂等待读/写消息的任务LosTaskCB
......@@ -97,13 +121,20 @@ STATIC const struct file_operations_vfs g_liteIpcFops = {
.mmap = LiteIpcMmap, /* mmap */
};
/*!
* @brief OsLiteIpcInit 初始化LiteIPC模块
*
* @return
*
* @see
*/
LITE_OS_SEC_TEXT_INIT UINT32 OsLiteIpcInit(VOID)
{
UINT32 ret;
#if (USE_TASKID_AS_HANDLE == YES)
g_cmsTask.status = HANDLE_NOT_USED;
#if (USE_TASKID_AS_HANDLE == YES) //两种管理方式,一种是 任务ID == service ID
g_cmsTask.status = HANDLE_NOT_USED;//默认未使用
#else
memset_s(g_serviceHandleMap, sizeof(g_serviceHandleMap), 0, sizeof(g_serviceHandleMap));
memset_s(g_serviceHandleMap, sizeof(g_serviceHandleMap), 0, sizeof(g_serviceHandleMap));//默认未使用
#endif
ret = LOS_MuxInit(&g_serviceHandleMapMux, NULL);
if (ret != LOS_OK) {
......@@ -243,7 +274,7 @@ ERROR_REGION_OUT:
ipcInfo->pool.kvaddr = NULL;
return ret;
}
///ipc内存池初始化
///初始化进程的IPC消息内存池
LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo)
{
ipcInfo->pool.uvaddr = NULL;
......@@ -253,7 +284,7 @@ LITE_OS_SEC_TEXT_INIT STATIC UINT32 LiteIpcPoolInit(ProcIpcInfo *ipcInfo)
LOS_ListInit(&ipcInfo->ipcUsedNodelist);
return LOS_OK;
}
///创建OPC消息内存池
LITE_OS_SEC_TEXT_INIT STATIC ProcIpcInfo *LiteIpcPoolCreate(VOID)
{
ProcIpcInfo *ipcInfo = LOS_MemAlloc(m_aucSysMem1, sizeof(ProcIpcInfo));
......@@ -266,7 +297,7 @@ LITE_OS_SEC_TEXT_INIT STATIC ProcIpcInfo *LiteIpcPoolCreate(VOID)
(VOID)LiteIpcPoolInit(ipcInfo);
return ipcInfo;
}
/// 重新初始化进程的IPC消息内存池
LITE_OS_SEC_TEXT ProcIpcInfo *LiteIpcPoolReInit(const ProcIpcInfo *parent)
{
ProcIpcInfo *ipcInfo = LiteIpcPoolCreate();
......@@ -280,7 +311,7 @@ LITE_OS_SEC_TEXT ProcIpcInfo *LiteIpcPoolReInit(const ProcIpcInfo *parent)
ipcInfo->ipcTaskID = INVAILD_ID;
return ipcInfo;
}
/// 释放进程的IPC消息内存池
STATIC VOID LiteIpcPoolDelete(ProcIpcInfo *ipcInfo, UINT32 processID)
{
UINT32 intSave;
......@@ -320,7 +351,7 @@ LITE_OS_SEC_TEXT UINT32 LiteIpcPoolDestroy(UINT32 processID)
pcb->ipcInfo = NULL;
return LOS_OK;
}
/// 申请并初始化一个任务IPC
LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfo *LiteIpcTaskInit(VOID)
{
IpcTaskInfo *taskInfo = LOS_MemAlloc((VOID *)m_aucSysMem1, sizeof(IpcTaskInfo));
......@@ -332,7 +363,7 @@ LITE_OS_SEC_TEXT_INIT STATIC IpcTaskInfo *LiteIpcTaskInit(VOID)
LOS_ListInit(&taskInfo->msgListHead);
return taskInfo;
}
///只有当内核不再访问ipc节点内容时,用户才能释放ipc节点
/// 只有当内核不再访问ipc节点内容时,用户才能释放ipc节点
/* Only when kernel no longer access ipc node content, can user free the ipc node */
LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser(UINT32 processID, VOID *buf)//用户释放一个在使用的IPC节点
{
......@@ -342,11 +373,11 @@ LITE_OS_SEC_TEXT STATIC VOID EnableIpcNodeFreeByUser(UINT32 processID, VOID *buf
if (node != NULL) {
node->ptr = buf;
IPC_LOCK(intSave);
LOS_ListAdd(&ipcInfo->ipcUsedNodelist, &node->list);
LOS_ListAdd(&ipcInfo->ipcUsedNodelist, &node->list);//
IPC_UNLOCK(intSave);
}
}
///分配一个IPC节点
///从内核对内存中分配一个IPC节点
LITE_OS_SEC_TEXT STATIC VOID *LiteIpcNodeAlloc(UINT32 processID, UINT32 size)
{
VOID *ptr = LOS_MemAlloc(OS_PCB_FROM_PID(processID)->ipcInfo->pool.kvaddr, size);
......@@ -410,7 +441,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckUsedBuffer(const VOID *node, IpcListNode **o
*outPtr = (IpcListNode *)ptr;
return LOS_OK;
}
/// 获取任务ID
LITE_OS_SEC_TEXT STATIC UINT32 GetTid(UINT32 serviceHandle, UINT32 *taskID)
{
if (serviceHandle >= MAX_SERVICE_NUM) {
......@@ -422,8 +453,8 @@ LITE_OS_SEC_TEXT STATIC UINT32 GetTid(UINT32 serviceHandle, UINT32 *taskID)
(VOID)LOS_MuxUnlock(&g_serviceHandleMapMux);
return LOS_OK;
#else
if (g_serviceHandleMap[serviceHandle].status == HANDLE_REGISTED) {
*taskID = g_serviceHandleMap[serviceHandle].taskID;
if (g_serviceHandleMap[serviceHandle].status == HANDLE_REGISTED) {//必须得是已注册
*taskID = g_serviceHandleMap[serviceHandle].taskID;//获取已注册服务的任务ID
(VOID)LOS_MuxUnlock(&g_serviceHandleMapMux);
return LOS_OK;
}
......@@ -469,10 +500,19 @@ LITE_OS_SEC_TEXT STATIC VOID RefreshServiceHandle(UINT32 serviceHandle, UINT32 r
#endif
}
/*!
* @brief AddServiceAccess 配置访问权限
*
* @param serviceHandle
* @param taskID
* @return
*
* @see
*/
LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess(UINT32 taskID, UINT32 serviceHandle)
{
UINT32 serviceTid = 0;
UINT32 ret = GetTid(serviceHandle, &serviceTid);
UINT32 ret = GetTid(serviceHandle, &serviceTid);//通过服务获取所在任务
if (ret != LOS_OK) {
PRINT_ERR("Liteipc AddServiceAccess GetTid failed\n");
return ret;
......@@ -484,15 +524,15 @@ LITE_OS_SEC_TEXT STATIC UINT32 AddServiceAccess(UINT32 taskID, UINT32 serviceHan
PRINT_ERR("Liteipc AddServiceAccess ipc not create! pid %u tid %u\n", processID, tcb->taskID);
return -EINVAL;
}
tcb->ipcTaskInfo->accessMap[processID] = TRUE;
tcb->ipcTaskInfo->accessMap[processID] = TRUE;//允许任务给自己所属进程发送IPC消息
pcb->ipcInfo->access[serviceTid] = TRUE;
return LOS_OK;
}
/// 参数服务是否有访问当前进程的权限,实际中会有 A进程的任务去给B进程发送IPC信息,所以需要鉴权
LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess(UINT32 serviceHandle)
{
UINT32 serviceTid = 0;
UINT32 curProcessID = LOS_GetCurrProcessID();
UINT32 curProcessID = LOS_GetCurrProcessID();//获取当前进程ID
UINT32 ret;
if (serviceHandle >= MAX_SERVICE_NUM) {
return FALSE;
......@@ -500,12 +540,12 @@ LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess(UINT32 serviceHandle)
if (serviceHandle == 0) {
return TRUE;
}
ret = GetTid(serviceHandle, &serviceTid);
ret = GetTid(serviceHandle, &serviceTid);//获取参数服务所属任务ID
if (ret != LOS_OK) {
PRINT_ERR("Liteipc HasServiceAccess GetTid failed\n");
return FALSE;
}
if (OS_TCB_FROM_TID(serviceTid)->processID == curProcessID) {
if (OS_TCB_FROM_TID(serviceTid)->processID == curProcessID) {//如果任务所在进程就是当前进程,直接返回OK
return TRUE;
}
......@@ -533,7 +573,7 @@ LITE_OS_SEC_TEXT BOOL IsIpcTaskSet(VOID)
}
return TRUE;
}
///获取
/// 获取IPC任务ID
LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID(UINT32 processID, UINT32 *ipcTaskID)
{
if (OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID == INVAILD_ID) {
......@@ -542,7 +582,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID(UINT32 processID, UINT32 *ipcTaskID)
*ipcTaskID = OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID;
return LOS_OK;
}
///发送死亡消息
/// 发送死亡消息
LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHandle)
{
UINT32 ipcTaskID;
......@@ -570,7 +610,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHand
content.outMsg->code = 0;
return LiteIpcWrite(&content);
}
/// 删除指定的Service
LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle(UINT32 taskID)
{
UINT32 j;
......@@ -773,16 +813,16 @@ LITE_OS_SEC_TEXT STATIC UINT32 HandleSvc(UINT32 dstTid, const SpecialObj *obj, B
}
return LOS_OK;
}
/// 创建处理对象
LITE_OS_SEC_TEXT STATIC UINT32 HandleObj(UINT32 dstTid, SpecialObj *obj, BOOL isRollback)
{
UINT32 ret;
UINT32 processID = OS_TCB_FROM_TID(dstTid)->processID;
UINT32 processID = OS_TCB_FROM_TID(dstTid)->processID;//获取目标任务所在进程
switch (obj->type) {
case OBJ_FD:
case OBJ_FD://fd:文件描述符
ret = HandleFd(processID, obj, isRollback);
break;
case OBJ_PTR:
case OBJ_PTR://指针
ret = HandlePtr(processID, obj, isRollback);
break;
case OBJ_SVC:
......
......@@ -50,10 +50,10 @@ extern "C" {
句柄是给用户程序使用的一个数字凭证,能以小博大,通过柄
能牵动内核模块工作.
*/
#define LITEIPC_DRIVER "/dev/lite_ipc" ///< 设备位置
#define LITEIPC_DRIVER_MODE 0644
#define LITEIPC_DRIVER "/dev/lite_ipc" ///< 虚拟设备
#define LITEIPC_DRIVER_MODE 0644 ///< 对虚拟设备的访问权限 110100100 表示只有所属用户才有读写权限,其余都只能读
#define MAX_SERVICE_NUM LOSCFG_BASE_CORE_TSK_LIMIT ///< 最大服务数等于任务数 默认128
#define USE_TIMESTAMP YES
#define USE_TIMESTAMP YES ///< 使用时间戳
/**
* @enum HandleStatus
......@@ -90,14 +90,15 @@ typedef struct {
* @brief 进程IPC信息,见于进程结构体: LosProcessCB.ipcInfo
*/
typedef struct {
IpcPool pool; ///< ipc池
UINT32 ipcTaskID; //ipc任务ID
LOS_DL_LIST ipcUsedNodelist;
IpcPool pool; ///< ipc池
UINT32 ipcTaskID; ///< ipc任务ID
LOS_DL_LIST ipcUsedNodelist;///< 已使用节点链表
UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT]; ///< 访问的任务数组
} ProcIpcInfo;
typedef struct {
LOS_DL_LIST msgListHead;
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];
LOS_DL_LIST msgListHead;///< 上面挂的是一个个的 ipc节点
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT]; ///< 此处是不是应该用 LOSCFG_BASE_CORE_PROCESS_LIMIT ? @note_thinking
///< 任务是否可以给其他进程发送IPC消息
} IpcTaskInfo;
typedef enum {
......@@ -110,22 +111,22 @@ typedef struct {
UINT32 buffSz;
VOID *buff;
} BuffPtr;
/// svc 是啥哩? @note_thinking
typedef struct {
UINT32 handle;
UINT32 handle;
UINT32 token;
UINT32 cookie;
} SvcIdentity;
/// 对象内容体
typedef union {
UINT32 fd;
BuffPtr ptr;
UINT32 fd; ///< 文件描述符
BuffPtr ptr;///< 缓存的开始地址,即:指针
SvcIdentity svc;
} ObjContent;
/// 特殊对象
typedef struct {
ObjType type;
ObjContent content;
ObjType type; ///< 类型
ObjContent content;///< 内容
} SpecialObj;
/**
......@@ -184,8 +185,8 @@ typedef struct {
} IpcMsg;
typedef struct { //IPC 内容节点
IpcMsg msg; //内容体
LOS_DL_LIST listNode;//通过它挂到LosTaskCB.msgListHead链表上
IpcMsg msg; ///< 内容体
LOS_DL_LIST listNode; ///< 通过它挂到LosTaskCB.msgListHead链表上
} IpcListNode;
#define SEND (1 << 0) ///< 发送
......
......@@ -61,12 +61,12 @@ typedef struct {
} TELNTE_FIFO_S;
//远程登录设备结构体
typedef struct {
INT32 clientFd;
UINT32 id;
BOOL eventPend;
EVENT_CB_S eventTelnet;
INT32 clientFd; ///< 客户端文件句柄
UINT32 id;
BOOL eventPend; ///< 事件是否挂起
EVENT_CB_S eventTelnet; ///< 远程登录事件
wait_queue_head_t wait;
TELNTE_FIFO_S *cmdFifo; /* use a FIFO to store user's commands */
TELNTE_FIFO_S *cmdFifo; /* use a FIFO to store user's commands | 使用先进先出保存用户的命令*/
} TELNET_DEV_S;
extern INT32 TelnetTx(const CHAR *buf, UINT32 len);
......
......@@ -50,8 +50,8 @@
#include "fs/driver.h"
/* event: there are more commands left in the FIFO to run */
#define TELNET_EVENT_MORE_CMD 0x01
#define TELNET_DEV_DRV_MODE 0666
#define TELNET_EVENT_MORE_CMD 0x01 ///< 还有很多命令在FIFO中等待运行的事件
#define TELNET_DEV_DRV_MODE 0666 ///< 文件权限 chmod = 666
STATIC TELNET_DEV_S g_telnetDev;
STATIC EVENT_CB_S *g_event;
......@@ -193,6 +193,7 @@ STATIC INT32 TelnetClose(struct file *file)
/*
* Description : When a command resolver task trys to read the telnet device,
* this method is called, and it will take out user's commands from the FIFO to run.
* 当命令解析器任务尝试读取 telnet 设备时,调用这个方法,它会从FIFO中取出用户的命令来运行。
* Return : -1 --- On failure
* Non-negative integer --- length of commands taken out from the FIFO of the telnet device.
*/
......@@ -203,15 +204,15 @@ STATIC ssize_t TelnetRead(struct file *file, CHAR *buf, size_t bufLen)
TelnetLock();
telnetDev = GetTelnetDevByFile(file, FALSE);
telnetDev = GetTelnetDevByFile(file, FALSE);//获取远程登录实体
if ((buf == NULL) || (telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
TelnetUnlock();
return -1;
}
if (telnetDev->eventPend) {
if (telnetDev->eventPend) {//挂起时,读取
TelnetUnlock();
(VOID)LOS_EventRead(g_event, TELNET_EVENT_MORE_CMD, LOS_WAITMODE_OR, LOS_WAIT_FOREVER);
(VOID)LOS_EventRead(g_event, TELNET_EVENT_MORE_CMD, LOS_WAITMODE_OR, LOS_WAIT_FOREVER);//等待读取 TELNET_EVENT_MORE_CMD 事件
TelnetLock();
}
......@@ -351,7 +352,7 @@ INT32 TelnetedUnregister(VOID)
{
free(g_telnetDev.cmdFifo);
g_telnetDev.cmdFifo = NULL;
(VOID)unregister_driver(TELNET);
(VOID)unregister_driver(TELNET);//注销字符设备驱动
return 0;
}
......@@ -394,7 +395,8 @@ INT32 TelnetDevInit(INT32 clientFd)
return ret;
}
/* When closing the telnet client connection, reset the output console for tasks. */
/* When closing the telnet client connection, reset the output console for tasks. |
关闭 telnet 客户端连接时,重置任务的控制台信息。*/
INT32 TelnetDevDeinit(VOID)
{
INT32 ret;
......
/*!
* @file telnet_loop.c
* @brief
* @link
* @file telnet_loop.c
* @brief telnet实现过程
* @link RFC854 https://docs.huihoo.com/rfc/RFC854.txt @endlink
@verbatim
telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员,
是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的 能力。
......@@ -13,7 +13,41 @@
但仍然有很多别的系统可能采用了telnet方式来提供远程登录,因此弄清楚telnet客户端的使用方式仍是很有必要的。
telnet命令还可做别的用途,比如确定远程服务的状态,比如确定远程服务器的某个端口是否能访问。
下面几个编码对NVT打印机有确定意义:
名称 编码 意义
NULL (NUL) 0 没有操作
BELL (BEL) 7 产生一个可以看到或可以听到的信号(而不移动打印头。)
Back Space (BS) 8 向左移动打印头一个字符位置。
Horizontal Tab (HT) 9 把打印头移到下一个水平制表符停止的位置。它仍然没有指定每一方如何检测或者设定如何定位这样的制表符的停止位置。
Line Feed (LF) 10 打印头移到下一个打印行,但不改变打印头的水平位置。
Vertical Tab (VT) 11 把打印头移到下一个垂直制表符停止的位置。它仍然没有指定每一方如何检测或者设定如何定位这样的制表符的停止位置。
Form Feed (FF) 12 把打印头移到下一页的顶部,保持打印头在相同的水平位置上。
Carriage Return (CR) 13 把打印头移到当前行的左边 。
下面是所有已定义的TELNET命令。需要注意的是,这些代码和代码序列只有在前面跟一个IAC时才有意义。
------------------------------------------------------------------------
名称 代码 意义
------------------------------------------------------------------------
SE 240 子谈判参数的结束
NOP 241 空操作
Data Mark 242 一个同步信号的数据流部分。该命令的后面经常跟着一个TCP紧急通知
Break 243 NVT的BRK字符
Interrupt Process 244 IP功能.
Abort output 245 AO功能.
Are You There 246 AYT功能.
Erase character 247 EC功能.
Erase Line 248 EL功能.
Go ahead 249 GA信号.
SB 250 表示后面所跟的是对需要的选项的子谈判
WILL (option code) 251 表示希望开始使用或者确认所使用的是指定的选项。
WON'T (option code) 252 表示拒绝使用或者继续使用指定的选项。
DO (option code) 253 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。
DON'T (option code) 254 表示一方要求另一方停止使用,或者确认你不再希望另一方使用指定的选项。
IAC 255 Data Byte 255.
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
......@@ -76,15 +110,18 @@
/* TELNET commands in RFC854 */
#define TELNET_SB 250 /* Indicates that what follows is subnegotiation of the indicated option */
#define TELNET_WILL 251 /* Indicates the desire to perform the indicated option */
#define TELNET_DO 253 /* Indicates the request for the other party to perform the indicated option */
#define TELNET_IAC 255 /* Interpret as Command */
#define TELNET_SB 250 /* Indicates that what follows is subnegotiation of the indicated option
| 表示后面所跟的是对需要的选项的子谈判*/
#define TELNET_WILL 251 /* Indicates the desire to perform the indicated option
| 表示希望执行指定的选项*/
#define TELNET_DO 253 /* Indicates the request for the other party to perform the indicated option
| 表示一方要求另一方使用,或者确认你希望另一方使用指定的选项。*/
#define TELNET_IAC 255 /* Interpret as Command | 中断命令*/
/* telnet options in IANA */
#define TELNET_ECHO 1 /* Echo */
#define TELNET_SGA 3 /* Suppress Go Ahead */
#define TELNET_NAWS 31 /* Negotiate About Window Size */
#define TELNET_ECHO 1 /* Echo | 回显*/
#define TELNET_SGA 3 /* Suppress Go Ahead | 抑制继续进行*/
#define TELNET_NAWS 31 /* Negotiate About Window Size | 窗口大小*/
#define TELNET_NOP 0xf1 /* Unassigned in IANA, putty use this to keepalive */
#define LEN_IAC_CMD 2 /* Only 2 char: |IAC|cmd| */
......@@ -100,9 +137,9 @@
#define TELNET_ACCEPT_INTERVAL 200
/* client settings | 客户端设置*/
#define TELNET_CLIENT_POLL_TIMEOUT 2000
#define TELNET_CLIENT_READ_BUF_SIZE 256
#define TELNET_CLIENT_READ_FILTER_BUF_SIZE (8 * 1024)
#define TELNET_CLIENT_POLL_TIMEOUT 2000 //超时时间设置
#define TELNET_CLIENT_READ_BUF_SIZE 256 //读buf大小
#define TELNET_CLIENT_READ_FILTER_BUF_SIZE (8 * 1024) ///< buf大小
/* limitation: only support 1 telnet client connection */
STATIC volatile INT32 g_telnetClientFd = -1; /* client fd */
......@@ -111,7 +148,7 @@ STATIC volatile INT32 g_telnetClientFd = -1; /* client fd */
STATIC volatile INT32 g_telnetListenFd = -1; /* listen fd of telnetd */
/* each bit for a client connection, although only support 1 connection for now */
STATIC volatile UINT32 g_telnetMask = 0; //掩码
STATIC volatile UINT32 g_telnetMask = 0; //记录有任务打开了远程登录
/* taskID of telnetd */
STATIC atomic_t g_telnetTaskId = 0; ///< 任务ID
/* protect listenFd, clientFd etc. */
......@@ -127,7 +164,7 @@ VOID TelnetUnlock(VOID)
(VOID)pthread_mutex_unlock(&g_telnetMutex);
}
/* filter out iacs from client stream */
/* filter out iacs from client stream | 从客户端流中过滤*/
STATIC UINT8 *ReadFilter(const UINT8 *src, UINT32 srcLen, UINT32 *dstLen)
{
STATIC UINT8 buf[TELNET_CLIENT_READ_FILTER_BUF_SIZE];
......@@ -224,11 +261,11 @@ STATIC ssize_t WriteToFd(INT32 fd, const CHAR *src, size_t srcLen)
return (ssize_t)(srcLen - sizeLeft);
}
/* Try to remove the client device if there is any client connection */
/* Try to remove the client device if there is any client connection | 如果有任务在远程登录,尝试删除它*/
STATIC VOID TelnetClientClose(VOID)
{
/* check if there is any client connection */
if (g_telnetMask == 0) {
if (g_telnetMask == 0) {//没有任务在远程链接,
return;
}
(VOID)TelnetDevDeinit();
......@@ -330,7 +367,7 @@ STATIC INT32 TelnetClientPrepare(INT32 clientFd)
g_telnetClientFd = -1;
return -1;
}
g_telnetMask = 1;
g_telnetMask = 1;//表示有任务在远程登录
/* negotiate with client */
(VOID)WriteToFd(clientFd, (CHAR *)doEcho, sizeof(doEcho));
......
......@@ -359,13 +359,13 @@ unsigned int SysGetPID(void)
{
return LOS_GetCurrProcessID();
}
/// 为指定进程设置进程组ID
int SysSetProcessGroupID(unsigned int pid, unsigned int gid)
{
int ret;
if (pid == 0) {
pid = LOS_GetCurrProcessID();
if (pid == 0) {//无指定进程ID时 @note_thinking 此处会不会有风险, 直接返回会不会好些 ?
pid = LOS_GetCurrProcessID();//获取当前进程ID,给当前进程设置组ID
}
if (gid == 0) {
......@@ -381,7 +381,7 @@ int SysSetProcessGroupID(unsigned int pid, unsigned int gid)
return OsSetProcessGroupID(pid, gid);
}
/// 获取指定进程的组ID,为0时返回当前进程ID
int SysGetProcessGroupID(unsigned int pid)
{
if (pid == 0) {
......@@ -390,12 +390,12 @@ int SysGetProcessGroupID(unsigned int pid)
return LOS_GetProcessGroupID(pid);
}
/// 获取当前进程组ID
int SysGetCurrProcessGroupID(void)
{
return LOS_GetCurrProcessGroupID();
}
/// 获取用户ID
int SysGetUserID(void)
{
return LOS_GetUserID();
......
git add -A
git commit -m ' 开始注解Telnet(远程登录)模块
git commit -m ' 注解LiteIPC(轻量级进程间通信)模块
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册