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

开始对注解调整/规范,以便支持docxgen

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    博客输出站点(国内):http://weharmonyos.com
    博客输出站点(国外):https://weharmony.github.io
    注解文件系统:https://gitee.com/weharmony/third_party_NuttX
    注解协议栈:https://gitee.com/weharmony/third_party_lwip
    注解编译子系统:https://gitee.com/weharmony/build_lite
上级 0b054a40
......@@ -45,10 +45,10 @@ extern "C" {
* Description: the info struct after cmd parser
*/
typedef struct {//命令解析器
unsigned int paramCnt; /* count of para *///参数数量
CmdType cmdType; /* cmd type, judge cmd keyword *///命令类型
char cmdKeyword[CMD_KEY_LEN]; /* cmd keyword str *///关键字,最多16个字符
char *paramArray[CMD_MAX_PARAS];//参数内容,最多32个参数
unsigned int paramCnt; /**< count of para \n 参数数量*/
CmdType cmdType; /**< cmd type, judge cmd keyword \n 命令类型*/
char cmdKeyword[CMD_KEY_LEN]; /**< cmd keyword str \n 关键字,最多16个字符*/
char *paramArray[CMD_MAX_PARAS];/**< 参数内容,最多32个参数 */
} CmdParsed;
extern unsigned int OsCmdParse(char *cmdStr, CmdParsed *cmdParsed);
......
......@@ -45,30 +45,34 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**************************************************************************************************
https://blog.csdn.net/kuangyufei/article/details/109032636
https://blog.csdn.net/qq_38410730/article/details/81036768
虚拟内存空间中的地址叫做“虚拟地址”;而实际物理内存空间中的地址叫做“实际物理地址”或“物理地址”。处理器
运算器和应用程序设计人员看到的只是虚拟内存空间和虚拟地址,而处理器片外的地址总线看到的只是物理地址空间和物理地址。
MMU是 MemoryManagementUnit 的缩写即,内存管理单元.
MMU 的作用:
1. 将虚拟地址翻译成为物理地址,然后访问实际的物理地址
2. 访问权限控制
当处理器试图访问一个虚存页面时,首先到页表中去查询该页是否已映射到物理页框中,并记录在页表中。如果在,
则MMU会把页码转换成页框码,并加上虚拟地址提供的页内偏移量形成物理地址后去访问物理内存;如果不在,
则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),
接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。
如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上
相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效的地址,则表明进程在试图访问
一个不存在的虚拟地址,此时操作系统将终止此次访问。
**************************************************************************************************/
/**
* @file los_arch_mmu.h
* @brief 简介
* @details 细节
* @mainpage https://blog.csdn.net/kuangyufei/article/details/109032636
https://blog.csdn.net/qq_38410730/article/details/81036768
虚拟内存空间中的地址叫做“虚拟地址”;而实际物理内存空间中的地址叫做“实际物理地址”或“物理地址”。处理器
运算器和应用程序设计人员看到的只是虚拟内存空间和虚拟地址,而处理器片外的地址总线看到的只是物理地址空间和物理地址。
MMU是 MemoryManagementUnit 的缩写即,内存管理单元.
MMU 的作用:
1. 将虚拟地址翻译成为物理地址,然后访问实际的物理地址
2. 访问权限控制
当处理器试图访问一个虚存页面时,首先到页表中去查询该页是否已映射到物理页框中,并记录在页表中。如果在,
则MMU会把页码转换成页框码,并加上虚拟地址提供的页内偏移量形成物理地址后去访问物理内存;如果不在,
则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),
接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。
如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上
相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效的地址,则表明进程在试图访问
一个不存在的虚拟地址,此时操作系统将终止此次访问。
*/
typedef struct ArchMmu {//内存管理单元
LosMux mtx; /**< arch mmu page table entry modification mutex lock *///对页表操作的互斥量
VADDR_T *virtTtb; /**< translation table base virtual addr */ //注意:这里是个指针,内核操作都用这个地址
PADDR_T physTtb; /**< translation table base phys addr */ //注意:这里是个值,这个值是记录给MMU使用的,MMU只认它,内核是无法使用的
UINT32 asid; /**< TLB asid */ //标识进程用的,由mmu分配,有了它在mmu层面才知道是哪个进程的虚拟地址
LOS_DL_LIST ptList; /**< page table vm page list *///L1 为表头,后面挂的是n多L2
LosMux mtx; /**< arch mmu page table entry modification mutex lock \n 对页表操作的互斥量*/
VADDR_T *virtTtb; /**< translation table base virtual addr \n 注意:这里是个指针,内核操作都用这个地址*/
PADDR_T physTtb; /**< translation table base phys addr \n 注意:这里是个值,这个值是记录给MMU使用的,MMU只认它,内核是无法使用的*/
UINT32 asid; /**< TLB asid \n 标识进程用的,由mmu分配,有了它在mmu层面才知道是哪个进程的虚拟地址*/
LOS_DL_LIST ptList; /**< page table vm page list \n L1 为表头,后面挂的是n多L2*/
} LosArchMmu;
BOOL OsArchMmuInit(LosArchMmu *archMmu, VADDR_T *virtTtb);
......
此差异已折叠。
......@@ -37,104 +37,119 @@
#endif
#include "los_sched_pri.h"
#include "los_hook.h"
/******************************************************************************
基本概念
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,
这个过程就叫做中断。
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要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中断为内部使用,因此不建议用户去申请和创建。
******************************************************************************/
/**@file los_hwi.c
* @brief 硬中断主文件
* @details
* @attention
基本概念 \n
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中, \n
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务, \n
这个过程就叫做中断。 \n
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。 \n
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,将通过产生 \n
中断信号使CPU立即中断当前任务来响应中断请求。这样可以使CPU避免把大量时间耗费在等待、 \n
查询外设状态的操作上,大大提高系统实时性以及执行效率。 \n
中断特性: \n
中断共享,且可配置。 \n
中断嵌套,即高优先级的中断可抢占低优先级的中断,且可配置。 \n
使用独立中断栈,可配置。 \n
可配置支持的中断优先级个数。 \n
可配置支持的中断数。 \n
中断相关的硬件介绍 \n
与中断相关的硬件可以划分为三类:设备、中断控制器、CPU本身。 \n
设备 \n
发起中断的源,当设备需要请求CPU时,产生一个中断信号,该信号连接至中断控制器。 \n
中断控制器 \n
中断控制器是CPU众多外设中的一个,它一方面接收其它外设中断引脚的输入,另一方面, \n
它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源 \n
的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和 \n
GIC(General Interrupt Controller)。在ARM Cortex-M系列中使用的中断控制器是 \n
NVIC(Nested Vector Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。 \n
CPU \n
CPU会响应中断源的请求,中断当前正在执行的任务,转而执行中断处理程序。 \n
中断相关概念 \n
中断号 \n
每个中断请求信号都会有特定的标志,使得计算机能够判断是哪个设备提出的中断请求,这个标志就是中断号。 \n
中断请求 \n
“紧急事件”需向CPU提出申请(发一个电脉冲信号),要求中断,及要求CPU暂停当前执行的任务, \n
转而处理该“紧急事件”,这一申请过程称为中断请求。 \n
中断优先级 \n
为使系统能够及时响应并处理所有中断,系统根据中断时间的重要性和紧迫程度,将中断源分为若干个级别, \n
称作中断优先级。 \n
中断处理程序 \n
当外设产生中断请求后,CPU暂停当前的任务,转而响应中断申请,即执行中断处理程序。产生中断的每个设备 \n
都有相应的中断处理程序。 \n
中断嵌套 \n
中断嵌套也称为中断抢占,指的是正在执行一个中断处理程序时,如果有另一个优先级更高的中断源提出中断请求, \n
这时会暂时终止当前正在执行的优先级较低的中断源的中断处理程序,转而去处理更高优先级的中断请求,待处理完毕, \n
再返回到之前被中断的处理程序中继续执行。 \n
中断触发 \n
中断源向中断控制器发送中断信号,中断控制器对中断进行仲裁,确定优先级,将中断信号送给CPU。 \n
中断源产生中断信号的时候,会将中断触发器置“1”,表明该中断源产生了中断,要求CPU去响应该中断。 \n
中断触发类型 \n
外部中断申请通过一个物理信号发送到NVIC/GIC,可以是电平触发或边沿触发。 \n
中断向量 \n
中断服务程序的入口地址。 \n
中断向量表 \n
存储中断向量的存储区,中断向量与中断号对应,中断向量在中断向量表中按照中断号顺序存储。 \n
中断共享 \n
当外设较少时,可以实现一个外设对应一个中断号,但为了支持更多的硬件设备,可以让多个设备共享 \n
一个中断号,共享同一个中断号的中断处理程序形成一个链表。当外部设备产生中断申请时,系统会 \n
遍历执行中断号对应的中断处理程序链表直到找到对应设备的中断处理程序。在遍历执行过程中, \n
各中断处理程序可以通过检测设备ID,判断是否是这个中断处理程序对应的设备产生的中断。 \n
核间中断 \n
对于多核系统,中断控制器允许一个CPU的硬件线程去中断其他CPU的硬件线程,这种方式被称为核间中断。 \n
核间中断的实现基础是多CPU内存共享,采用核间中断可以减少某个CPU负荷过大,有效提升系统效率。 \n
目前只有GIC中断控制器支持。 \n
使用场景 \n
当有中断请求产生时,CPU暂停当前的任务,转而去响应外设请求。根据需要,用户通过 \n
中断申请,注册中断处理程序,可以指定CPU响应中断请求时所执行的具体操作。 \n
开发流程 \n
调用中断创建接口LOS_HwiCreate创建中断。 \n \n
如果是SMP模式,调用LOS_HwiSetAffinity设置中断的亲和性,否则直接进入步骤4。 \n
调用LOS_HwiEnable接口使能指定中断。 \n
调用LOS_HwiTrigger接口触发指定中断(该接口通过写中断控制器的相关寄存器模拟外部中断,一般的外设设备,不需要执行这一步)。 \n
调用LOS_HwiDisable接口屏蔽指定中断,此接口根据实际情况使用,判断是否需要屏蔽中断。 \n
调用LOS_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。 \n
注意事项 \n
根据具体硬件,配置支持的最大中断数及可设置的中断优先级个数。 \n
中断共享机制,支持不同的设备使用相同的中断号注册同一中断处理程序,但中断处理程序的入参pDevId(设备号) \n
必须唯一,代表不同的设备。即同一中断号,同一dev只能挂载一次;但同一中断号,同一中断处理程序,dev不同则可以重复挂载。 \n
中断处理程序耗时不能过长,否则会影响CPU对中断的及时响应。 \n
中断响应过程中不能执行引起调度的函数。 \n
中断恢复LOS_IntRestore()的入参必须是与之对应的LOS_IntLock()的返回值(即关中断之前的CPSR值)。 \n
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。 \n
*/
/* spinlock for hwi module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_hwiSpin); //注意全局变量 g_hwiSpin 是在宏里面定义的
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};//记录每个硬中断的总数量
VOID OsIncHwiFormCnt(UINT32 index) //增加一个中断数,递增的,所以只有++ ,没有--,
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]++;
}
UINT32 OsGetHwiFormCnt(UINT32 index)//获取某个中断的中断次数
/**
* @brief 获取某个中断的中断次数
*
* @param index
* @return UINT32
*/
UINT32 OsGetHwiFormCnt(UINT32 index)
{
return g_hwiFormCnt[index];
}
......
......@@ -55,6 +55,7 @@ extern "C" {
*/ //在LPC2458平台上发生异常时存储的寄存器信息 以下不带uw的寄存器名是芯片手册中使用的寄存器名
#ifdef LOSCFG_ARCH_ARM_AARCH64
#define EXC_GEN_REGS_NUM 30
typedef struct {
UINT64 X[EXC_GEN_REGS_NUM]; /**< Register X0-X29 */
UINT64 LR; /**< Program returning address. X30 */
......
......@@ -327,7 +327,14 @@ STATIC BOOL OsWaitWakeSpecifiedProcess(LOS_DL_LIST *head, const LosProcessCB *pr
return find;
}
//检查父进程的等待任务并唤醒父进程去处理等待任务
/**
* @brief 检查父进程的等待任务并唤醒父进程去处理等待任务
*
* @param parentCB
* @param processCB
* @return STATIC
*/
STATIC VOID OsWaitCheckAndWakeParentProcess(LosProcessCB *parentCB, const LosProcessCB *processCB)
{
LOS_DL_LIST *head = &parentCB->waitList;
......@@ -338,7 +345,7 @@ STATIC VOID OsWaitCheckAndWakeParentProcess(LosProcessCB *parentCB, const LosPro
if (LOS_ListEmpty(&parentCB->waitList)) {//父进程中是否有在等待子进程退出的任务?
return;//没有就退出
}
// TODO
findSpecified = OsWaitWakeSpecifiedProcess(head, processCB, &list);//找到指定的任务
if (findSpecified == TRUE) {
/* No thread is waiting for any child process to finish */
......
......@@ -29,6 +29,67 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**@file los_swtmr.c
* @brief 软定时器主文件
* @details
* @attention 基本概念 \n
软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器。当经过设定的Tick数后,会触发用户自定义的回调函数。\n
硬件定时器受硬件的限制,数量上不足以满足用户的实际需求。因此为了满足用户需求,提供更多的定时器,\n
软件定时器功能,支持如下特性:\n
创建软件定时器。\n
启动软件定时器。\n
停止软件定时器。\n
删除软件定时器。\n
获取软件定时器剩余Tick数。\n
可配置支持的软件定时器个数。\n
运作机制 \n
软件定时器是系统资源,在模块初始化的时候已经分配了一块连续内存。\n
软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,\n
先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先触发的准则。\n
软件定时器以Tick为基本计时单位,当创建并启动一个软件定时器时,Huawei LiteOS会根据 \n
当前系统Tick时间及设置的定时时长确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。\n
当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,检查是否有定时器超时,\n
若有则将超时的定时器记录下来。Tick中断处理函数结束后,软件定时器任务(优先级为最高)\n
被唤醒,在该任务中调用已经记录下来的定时器的回调函数。\n
定时器状态 \n
OS_SWTMR_STATUS_UNUSED(定时器未使用)\n
系统在定时器模块初始化时,会将系统中所有定时器资源初始化成该状态。\n
OS_SWTMR_STATUS_TICKING(定时器处于计数状态)\n
在定时器创建后调用LOS_SwtmrStart接口启动,定时器将变成该状态,是定时器运行时的状态。\n
OS_SWTMR_STATUS_CREATED(定时器创建后未启动,或已停止)\n
定时器创建后,不处于计数状态时,定时器将变成该状态。\n
软件定时器提供了三类模式:\n
单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。\n
周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。\n
单次触发定时器,但这类定时器超时触发后不会自动删除,需要调用定时器删除接口删除定时器。\n
使用场景 \n
创建一个单次触发的定时器,超时后执行用户自定义的回调函数。\n
创建一个周期性触发的定时器,超时后执行用户自定义的回调函数。\n
软件定时器的典型开发流程 \n
通过make menuconfig配置软件定时器 \n
创建定时器LOS_SwtmrCreate,设置定时器的定时时长、定时器模式、超时后的回调函数。\n
启动定时器LOS_SwtmrStart。\n
获得软件定时器剩余Tick数LOS_SwtmrTimeGet。\n
停止定时器LOS_SwtmrStop。\n
删除定时器LOS_SwtmrDelete。\n
注意事项 \n
软件定时器的回调函数中不应执行过多操作,不建议使用可能引起任务挂起或者阻塞的接口或操作, \n
如果使用会导致软件定时器响应不及时,造成的影响无法确定。\n
软件定时器使用了系统的一个队列和一个任务资源。软件定时器任务的优先级设定为0,且不允许修改 。\n
系统可配置的软件定时器个数是指:整个系统可使用的软件定时器总个数,并非用户可使用的软件定时器个数。\n
例如:系统多占用一个软件定时器,那么用户能使用的软件定时器资源就会减少一个。\n
创建单次不自删除属性的定时器,用户需要自行调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。\n
软件定时器的定时精度与系统Tick时钟的周期有关。\n
*/
#include "los_swtmr_pri.h"
#include "los_init.h"
#include "los_process_pri.h"
......@@ -37,82 +98,26 @@
#include "los_sortlink_pri.h"
#include "los_task_pri.h"
#include "los_hook.h"
/******************************************************************************
基本概念
软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器。当经过设定的Tick数后,
会触发用户自定义的回调函数。
硬件定时器受硬件的限制,数量上不足以满足用户的实际需求。因此为了满足用户需求,
提供更多的定时器,
软件定时器功能,支持如下特性:
创建软件定时器。
启动软件定时器。
停止软件定时器。
删除软件定时器。
获取软件定时器剩余Tick数。
可配置支持的软件定时器个数。
运作机制
软件定时器是系统资源,在模块初始化的时候已经分配了一块连续内存。
软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,
先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先触发的准则。
软件定时器以Tick为基本计时单位,当创建并启动一个软件定时器时,Huawei LiteOS会根据
当前系统Tick时间及设置的定时时长确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。
当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,检查是否有定时器超时,
若有则将超时的定时器记录下来。Tick中断处理函数结束后,软件定时器任务(优先级为最高)
被唤醒,在该任务中调用已经记录下来的定时器的回调函数。
定时器状态
OS_SWTMR_STATUS_UNUSED(定时器未使用)
系统在定时器模块初始化时,会将系统中所有定时器资源初始化成该状态。
OS_SWTMR_STATUS_TICKING(定时器处于计数状态)
在定时器创建后调用LOS_SwtmrStart接口启动,定时器将变成该状态,是定时器运行时的状态。
OS_SWTMR_STATUS_CREATED(定时器创建后未启动,或已停止)
定时器创建后,不处于计数状态时,定时器将变成该状态。
软件定时器提供了三类模式:
单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。
周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。
单次触发定时器,但这类定时器超时触发后不会自动删除,需要调用定时器删除接口删除定时器。
使用场景
创建一个单次触发的定时器,超时后执行用户自定义的回调函数。
创建一个周期性触发的定时器,超时后执行用户自定义的回调函数。
软件定时器的典型开发流程
通过make menuconfig配置软件定时器
创建定时器LOS_SwtmrCreate,设置定时器的定时时长、定时器模式、超时后的回调函数。
启动定时器LOS_SwtmrStart。
获得软件定时器剩余Tick数LOS_SwtmrTimeGet。
停止定时器LOS_SwtmrStop。
删除定时器LOS_SwtmrDelete。
注意事项
软件定时器的回调函数中不应执行过多操作,不建议使用可能引起任务挂起或者阻塞的接口或操作,
如果使用会导致软件定时器响应不及时,造成的影响无法确定。
软件定时器使用了系统的一个队列和一个任务资源。软件定时器任务的优先级设定为0,且不允许修改 。
系统可配置的软件定时器个数是指:整个系统可使用的软件定时器总个数,并非用户可使用的软件定时器个数。
例如:系统多占用一个软件定时器,那么用户能使用的软件定时器资源就会减少一个。
创建单次不自删除属性的定时器,用户需要自行调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。
软件定时器的定时精度与系统Tick时钟的周期有关。
******************************************************************************/
#ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
#if (LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0)
#error "swtmr maxnum cannot be zero"
#endif /* LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0 */
LITE_OS_SEC_BSS SWTMR_CTRL_S *g_swtmrCBArray = NULL; /* First address in Timer memory space *///定时器池
LITE_OS_SEC_BSS UINT8 *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler *///用于注册软时钟的回调函数
LITE_OS_SEC_BSS LOS_DL_LIST g_swtmrFreeList; /* Free list of Software Timer *///空闲定时器链表
LITE_OS_SEC_BSS SWTMR_CTRL_S *g_swtmrCBArray = NULL; /**< First address in Timer memory space \n 定时器池 */
LITE_OS_SEC_BSS UINT8 *g_swtmrHandlerPool = NULL; /**< Pool of Swtmr Handler \n 用于注册软时钟的回调函数 */
LITE_OS_SEC_BSS LOS_DL_LIST g_swtmrFreeList; /**< Free list of Software Timer \n 空闲定时器链表 */
/* spinlock for swtmr module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin);//初始化软时钟自旋锁,只有SMP情况才需要,只要是自旋锁都是用于CPU多核的同步
#define SWTMR_LOCK(state) LOS_SpinLockSave(&g_swtmrSpin, &(state))//持有软时钟自旋锁
#define SWTMR_UNLOCK(state) LOS_SpinUnlockRestore(&g_swtmrSpin, (state))//释放软时钟自旋锁
//软时钟的入口函数,拥有任务的最高优先级 0 级!
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin);///< 初始化软时钟自旋锁,只有SMP情况才需要,只要是自旋锁都是用于CPU多核的同步
#define SWTMR_LOCK(state) LOS_SpinLockSave(&g_swtmrSpin, &(state))///< 持有软时钟自旋锁
#define SWTMR_UNLOCK(state) LOS_SpinUnlockRestore(&g_swtmrSpin, (state))///< 释放软时钟自旋锁
/**
* @brief 软时钟的入口函数,拥有任务的最高优先级 0 级!
*
* @return LITE_OS_SEC_TEXT
*/
LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID)
{
SwtmrHandlerItemPtr swtmrHandlePtr = NULL;
......@@ -234,9 +239,9 @@ ERROR:
}
/*
* Description: Start Software Timer
* Description: Start Software Timer \n 开始定时器
* Input : swtmr --- Need to start software timer
*/ //开始定时器
*/
LITE_OS_SEC_TEXT VOID OsSwtmrStart(UINT64 currTime, SWTMR_CTRL_S *swtmr)
{
UINT32 ticks;
......
......@@ -32,51 +32,69 @@
#include "los_sys_pri.h"
#include "los_sched_pri.h"
/******************************************************************************
基本概念
时间管理以系统时钟为基础,给应用程序提供所有和时间有关的服务。
/**@file los_sys.c
* @brief 系统时间转化
* @details
* @attention
基本概念 \n
时间管理以系统时钟为基础,给应用程序提供所有和时间有关的服务。\n
系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。
输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。
系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。\n
输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。\n
用户以秒、毫秒为单位计时,而操作系统以Tick为单位计时,当用户需要对系统进行操作时,
例如任务挂起、延时等,此时需要时间管理模块对Tick和秒/毫秒进行转换。
时间管理模块提供时间转换、统计、延迟功能
用户以秒、毫秒为单位计时,而操作系统以Tick为单位计时,当用户需要对系统进行操作时,\n
例如任务挂起、延时等,此时需要时间管理模块对Tick和秒/毫秒进行转换。\n
时间管理模块提供时间转换、统计、延迟功能\n
相关概念
Cycle
系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数。
相关概念 \n
Cycle \n
系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数。\n
Tick
Tick是操作系统的基本时间单位,由用户配置的每秒Tick数决定。
Tick \n
Tick是操作系统的基本时间单位,由用户配置的每秒Tick数决定。\n
使用场景
用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系等。
使用场景 \n
用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系等。 \n
时间管理的典型开发流程
根据实际需求,在板级配置适配时确认是否使能LOSCFG_BASE_CORE_TICK_HW_TIME宏选择外部定时器,
并配置系统主时钟频率OS_SYS_CLOCK(单位Hz)。OS_SYS_CLOCK的默认值基于硬件平台配置。
通过make menuconfig配置LOSCFG_BASE_CORE_TICK_PER_SECOND。
注意事项
时间管理不是单独的功能模块,依赖于OS_SYS_CLOCK和LOSCFG_BASE_CORE_TICK_PER_SECOND两个配置选项。
系统的Tick数在关中断的情况下不进行计数,故系统Tick数不能作为准确时间使用。
时间管理的典型开发流程 \n
根据实际需求,在板级配置适配时确认是否使能LOSCFG_BASE_CORE_TICK_HW_TIME宏选择外部定时器,\n
并配置系统主时钟频率OS_SYS_CLOCK(单位Hz)。OS_SYS_CLOCK的默认值基于硬件平台配置。\n
通过make menuconfig配置LOSCFG_BASE_CORE_TICK_PER_SECOND。\n
注意事项 \n
时间管理不是单独的功能模块,依赖于OS_SYS_CLOCK和LOSCFG_BASE_CORE_TICK_PER_SECOND两个配置选项。\n
系统的Tick数在关中断的情况下不进行计数,故系统Tick数不能作为准确时间使用。\n
参考 \n
https://gitee.com/LiteOS/LiteOS/blob/master/doc/Huawei_LiteOS_Kernel_Developer_Guide_zh.md#setup\n
*/
参考
https://gitee.com/LiteOS/LiteOS/blob/master/doc/Huawei_LiteOS_Kernel_Developer_Guide_zh.md#setup
******************************************************************************/
#define OS_MAX_VALUE 0xFFFFFFFFUL
//获取自系统启动以来的Tick数
/**
* @brief 获取自系统启动以来的Tick数
*
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
{
return OsGetCurrSchedTimeCycle() / OS_CYCLE_PER_TICK;
}
//每个Tick多少Cycle数
/**
* @brief 每个Tick多少Cycle数
*
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
{
return g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
//毫秒转换成Tick
/**
* @brief 毫秒转换成Tick
*
* @param millisec
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
{
if (millisec == OS_MAX_VALUE) {
......@@ -85,12 +103,22 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND;
}
//Tick转化为毫秒
/**
* @brief Tick转化为毫秒
*
* @param tick
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 tick)
{
return ((UINT64)tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
/**
* @brief 纳秒转化成 tick
*
* @param nanoseconds
* @return LITE_OS_SEC_TEXT_MINOR
*/
LITE_OS_SEC_TEXT_MINOR UINT32 OsNS2Tick(UINT64 nanoseconds)
{
const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
......
......@@ -37,12 +37,12 @@
#endif
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;//系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;//每秒Tick数,鸿蒙默认是每秒100次,即:10ms
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; //周期转纳秒级
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;///< 系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;///<每秒Tick数,鸿蒙默认是每秒100次,即:10ms
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; ///<周期转纳秒级
/* spinlock for task module */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); //节拍器自旋锁
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); ///<节拍器自旋锁
/*
* Description : Tick interruption handler
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册