规范和补充中断,定时器,互斥量,信号量模块注解.

搜索 @note_pic 方便理解画的字符图
搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善
搜索 @note_thinking 一点思考和吐槽的地方
搜索 @note_#if0 由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的
搜索 @note_good 给源码点赞
上级 ddf4faac
......@@ -43,6 +43,88 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
基本概念
中断是指出现需要时,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中断为内部使用,因此不建议用户去申请和创建。
******************************************************************************/
/* 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))
......@@ -303,7 +385,11 @@ LITE_OS_SEC_TEXT_INIT VOID OsHwiInit(VOID)//硬件中断初始化
return;
}
//创建一个硬中断
/******************************************************************************
创建一个硬中断
中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,
handleIrq会调用该中断处理程序
******************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum, //硬中断句柄编号 默认范围[0-127]
HWI_PRIOR_T hwiPrio, //硬中断优先级
HWI_MODE_T hwiMode, //硬中断模式 共享和非共享
......
......@@ -282,8 +282,8 @@ extern HwiHandleForm g_hwiForm[OS_HWI_MAX_NUM];
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see LOS_IntRestore
*/
STATIC INLINE UINT32 LOS_IntLock(VOID)//在所有中断被禁用之前获得的CPSR值 /|\
*/ //关闭当前处理器所有中断响应
STATIC INLINE UINT32 LOS_IntLock(VOID)
{//此API用于禁用CPSR中的所有IRQ和FIQ中断。CPSR:程序状态寄存器(current program status register)
return ArchIntLock();
}//IRQ(Interrupt Request):指中断模式。FIQ(Fast Interrupt Request):指快速中断模式。
......@@ -307,8 +307,8 @@ STATIC INLINE UINT32 LOS_IntLock(VOID)//在所有中断被禁用之前获得的C
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see LOS_IntLock
*/
STATIC INLINE UINT32 LOS_IntUnLock(VOID)//启用所有中断后获得的CPSR值
*/ //打开当前处理器所有中断响应
STATIC INLINE UINT32 LOS_IntUnLock(VOID)
{//此API用于启用CPSR中的所有IRQ和FIQ中断。
return ArchIntUnlock();
}
......@@ -333,8 +333,8 @@ STATIC INLINE UINT32 LOS_IntUnLock(VOID)//启用所有中断后获得的CPSR值
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see LOS_IntLock
*/
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)//在所有中断被禁用之前获得的CPSR值
*/ //恢复到使用LOS_IntLock关闭所有中断之前的状态
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)
{//只有在禁用所有中断之后才能调用此API,并且输入参数值应为LOS_IntLock返回的值。
ArchIntRestore(intSave);
}
......@@ -375,7 +375,7 @@ STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)//在所有中断被禁用之
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see None.
*/
*/ //中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,handleIrq会调用该中断处理程序
extern UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum,
HWI_PRIOR_T hwiPrio,
HWI_MODE_T hwiMode,
......@@ -410,7 +410,7 @@ extern UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum,
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see None.
*/
*/ //删除中断
extern UINT32 LOS_HwiDelete(HWI_HANDLE_T hwiNum, HwiIrqParam *irqParam);
#ifdef __cplusplus
......
......@@ -41,6 +41,68 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
基本概念
软件定时器,是基于系统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时钟的周期有关。
******************************************************************************/
#if (LOSCFG_BASE_CORE_SWTMR == YES)
#if (LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0)
#error "swtmr maxnum cannot be zero"
......
......@@ -37,7 +37,39 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
基本概念
时间管理以系统时钟为基础,给应用程序提供所有和时间有关的服务。
系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。
输出脉冲的周期叫做一个“时钟滴答”。系统时钟也称为时标或者Tick。
用户以秒、毫秒为单位计时,而操作系统以Tick为单位计时,当用户需要对系统进行操作时,
例如任务挂起、延时等,此时需要时间管理模块对Tick和秒/毫秒进行转换。
时间管理模块提供时间转换、统计、延迟功能
相关概念
Cycle
系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数。
Tick
Tick是操作系统的基本时间单位,由用户配置的每秒Tick数决定。
使用场景
用户需要了解当前系统运行的时间以及Tick与秒、毫秒之间的转换关系等。
时间管理的典型开发流程
根据实际需求,在板级配置适配时确认是否使能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数不能作为准确时间使用。
参考
https://gitee.com/LiteOS/LiteOS/blob/master/doc/Huawei_LiteOS_Kernel_Developer_Guide_zh.md#setup
******************************************************************************/
#define OS_MAX_VALUE 0xFFFFFFFF
//获取自系统启动以来的Tick数
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
......
......@@ -44,6 +44,49 @@
extern "C" {
#endif
#endif /* __cplusplus */
/******************************************************************************
事件(Event)是一种任务间通信的机制,可用于任务间的同步。
多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。
一对多同步模型:一个任务等待多个事件的触发。可以是任意一个事件发生时唤醒任务处理事件,也可以是几个事件都发生后才唤醒任务处理事件。
多对多同步模型:多个任务等待多个事件的触发。
事件特点
任务通过创建事件控制块来触发事件或等待事件。
事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。
事件仅用于任务间的同步,不提供数据传输功能。
多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。
多个任务可以对同一事件进行读写操作。
支持事件读写超时机制。
事件读取模式
在读事件时,可以选择读取模式。读取模式如下:
所有事件(LOS_WAITMODE_AND):逻辑与,基于接口传入的事件类型掩码eventMask,
只有这些事件都已经发生才能读取成功,否则该任务将阻塞等待或者返回错误码。
任一事件(LOS_WAITMODE_OR):逻辑或,基于接口传入的事件类型掩码eventMask,
只要这些事件中有任一种事件发生就可以读取成功,否则该任务将阻塞等待或者返回错误码。
清除事件(LOS_WAITMODE_CLR):这是一种附加读取模式,需要与所有事件模式或任一事件模式结合
使用(LOS_WAITMODE_AND | LOS_WAITMODE_CLR或 LOS_WAITMODE_OR | LOS_WAITMODE_CLR)。在这种模式下,
当设置的所有事件模式或任一事件模式读取成功后,会自动清除事件控制块中对应的事件类型位。
运作机制
任务在调用LOS_EventRead接口读事件时,可以根据入参事件掩码类型eventMask读取事件的单个或者多个事件类型。
事件读取成功后,如果设置LOS_WAITMODE_CLR会清除已读取到的事件类型,反之不会清除已读到的事件类型,需显式清除。
可以通过入参选择读取模式,读取事件掩码类型中所有事件还是读取事件掩码类型中任意事件。
任务在调用LOS_EventWrite接口写事件时,对指定事件控制块写入指定的事件类型,
可以一次同时写多个事件类型。写事件会触发任务调度。
任务在调用LOS_EventClear接口清除事件时,根据入参事件和待清除的事件类型,
对事件对应位进行清0操作。
使用场景
事件可应用于多种任务同步场景,在某些同步场景下可替代信号量。
注意事项
在系统初始化之前不能调用读写事件接口。如果调用,系统运行会不正常。
在中断中,可以对事件对象进行写操作,但不能进行读操作。
在锁任务调度状态下,禁止任务阻塞于读事件。
LOS_EventClear 入参值是:要清除的指定事件类型的反码(~events)。
为了区别LOS_EventRead接口返回的是事件还是错误码,事件掩码的第25位不能使用。
******************************************************************************/
//初始化一个事件控制块
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
......
......@@ -42,6 +42,57 @@ extern "C" {
#endif
#endif /* __cplusplus */
/******************************************************************************
基本概念
互斥锁又称互斥型信号量,是一种特殊的二值性信号量,用于实现对临界资源的独占式处理。
另外,互斥锁可以解决信号量存在的优先级翻转问题。
任意时刻互斥锁只有两种状态,开锁或闭锁。当任务持有时,这个任务获得该互斥锁的所有权,
互斥锁处于闭锁状态。当该任务释放锁后,任务失去该互斥锁的所有权,互斥锁处于开锁状态。
当一个任务持有互斥锁时,其他任务不能再对该互斥锁进行开锁或持有。
互斥锁具有特点
通过优先级继承算法,解决优先级翻转问题。
多任务阻塞等待同一个锁的场景,支持基于任务优先级等待和FIFO两种模式。
运作机制
多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的临界资源,
只能被独占使用。互斥锁怎样来避免这种冲突呢?
用互斥锁处理临界资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务
如果想访问这个临界资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问
该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个临界资源,保证了
临界资源操作的完整性。
使用场景
多任务环境下往往存在多个任务竞争同一临界资源的应用场景,互斥锁可以提供任务间的互斥机制,
防止两个任务在同一时刻访问相同的临界资源,从而实现独占式访问。
申请互斥锁有三种模式:无阻塞模式、永久阻塞模式、定时阻塞模式。
无阻塞模式:即任务申请互斥锁时,入参timeout等于0。若当前没有任务持有该互斥锁,
或者持有该互斥锁的任务和申请该互斥锁的任务为同一个任务,则申请成功,否则立即返回申请失败。
永久阻塞模式:即任务申请互斥锁时,入参timeout等于0xFFFFFFFF。若当前没有任务持有该互斥锁,
则申请成功。否则,任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,
直到有其他任务释放该互斥锁,阻塞任务才会重新得以执行。
定时阻塞模式:即任务申请互斥锁时,0<timeout<0xFFFFFFFF。若当前没有任务持有该互斥锁,则申请成功。
否则该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,超时前如果
有其他任务释放该互斥锁,则该任务可成功获取互斥锁继续执行,若超时前未获取到该互斥锁,接口将返回超时错误码。 释放互斥锁:
如果有任务阻塞于该互斥锁,则唤醒被阻塞任务中优先级最高的,该任务进入就绪态,并进行任务调度。
如果没有任务阻塞于该互斥锁,则互斥锁释放成功。
互斥锁开发流程
通过make menuconfig配置互斥锁模块。
创建互斥锁LOS_MuxCreate。
申请互斥锁LOS_MuxPend。
释放互斥锁LOS_MuxPost。
删除互斥锁LOS_MuxDelete。
注意事项
互斥锁不能在中断服务程序中使用。
Huawei LiteOS作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁。
持有互斥锁的过程中,不得再调用LOS_TaskPriSet等接口更改持有互斥锁任务的优先级。
互斥锁不支持多个相同优先级任务翻转的场景。
******************************************************************************/
#if (LOSCFG_BASE_IPC_MUX == YES)
#define MUTEXATTR_TYPE_MASK 0x0FU
//互斥属性初始化
......
......@@ -41,24 +41,52 @@
extern "C" {
#endif
#endif /* __cplusplus */
/************************************************
https://support.huaweicloud.com/kernelmanual-LiteOS/zh-cn_topic_0145350145.html
队列又称消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,
并根据不同的接口选择传递消息是否存放在自己空间。任务能够从队列里面读取消息,当队列中的消息是空时,
挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。
用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放入队列,但并不立即处理它,同时队列还能起到缓冲消息作用。
鸿蒙 LiteOS中使用队列数据结构实现任务异步通信工作,具有如下特性:
消息以先进先出方式排队,支持异步读写工作方式。
读队列和写队列都支持超时机制。
发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)消息。
一个任务能够从任意一个消息队列接收和发送消息。
多个任务能够从同一个消息队列接收和发送消息。
当队列使用结束后,如果是动态申请的内存,需要通过释放内存函数回收。
************************************************/
/******************************************************************************
基本概念
队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的
不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,
挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,
挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。如果将
读队列和写队列的超时时间设置为0,则不会挂起任务,接口会直接返回,这就是非阻塞模式。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。
队列特性
消息以先进先出的方式排队,支持异步读写。
读队列和写队列都支持超时机制。
每读取一条消息,就会将该消息节点设置为空闲。
发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。
一个任务能够从任意一个消息队列接收和发送消息。
多个任务能够从同一个消息队列接收和发送消息。
创建队列时所需的队列空间,默认支持接口内系统自行动态申请内存的方式,同时也支持将用户分配的队列空间作为接口入参传入的方式。
队列运作原理
创建队列时,创建队列成功会返回队列ID。
在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail来,用于表示当前
队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置。Tail表示被占用的
消息节点的结束位置,也是空闲消息节点的起始位置。队列刚创建时,Head和Tail均指向队列起始位置。
写队列时,根据readWriteableCnt[1]判断队列是否可以写入,不能对已满(readWriteableCnt[1]为0)
队列进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,
根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,
将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。
读队列时,根据readWriteableCnt[0]判断队列是否有消息需要读取,对全部空闲(readWriteableCnt[0]为0)
队列进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。
如果Head已经指向队列尾部则采用回卷方式。
删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态。
如果是通过系统动态申请内存方式创建的队列,还会释放队列所占内存。
使用场景
队列用于任务间通信,可以实现消息的异步处理。同时消息的发送方和接收方不需要彼此联系,两者间是解耦的。
队列错误码
对存在失败可能性的操作返回对应的错误码,以便快速定位错误原因。
******************************************************************************/
#if (LOSCFG_BASE_IPC_QUEUE == YES)
#if (LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0)
#error "queue maxnum cannot be zero"
......
......@@ -44,6 +44,58 @@ extern "C" {
#endif
#endif /* __cplusplus */
/******************************************************************************
基本概念
信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。
一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数,其值的含义分两种情况:
0,表示该信号量当前不可获取,因此可能存在正在等待该信号量的任务。
正值,表示该信号量当前可被获取。
以同步为目的的信号量和以互斥为目的的信号量在使用上有如下不同:
用作互斥时,初始信号量计数值不为0,表示可用的共享资源个数。在需要使用共享资源前,先获取信号量,
然后使用一个共享资源,使用完毕后释放信号量。这样在共享资源被取完,即信号量计数减至0时,其他
需要获取信号量的任务将被阻塞,从而保证了共享资源的互斥访问。另外,当共享资源数为1时,
建议使用二值信号量,一种类似于互斥锁的机制。
用作同步时,初始信号量计数值为0。任务1获取信号量而阻塞,直到任务2或者某中断释放信号量,
任务1才得以进入Ready或Running态,从而达到了任务间的同步。
信号量运作原理
信号量初始化,为配置的N个信号量申请内存(N值可以由用户自行配置,通过LOSCFG_BASE_IPC_SEM_LIMIT宏实现),
并把所有信号量初始化成未使用,加入到未使用链表中供系统使用。
信号量创建,从未使用的信号量链表中获取一个信号量,并设定初值。
信号量申请,若其计数器值大于0,则直接减1返回成功。否则任务阻塞,等待其它任务释放该信号量,
等待的超时时间可设定。当任务被一个信号量阻塞时,将该任务挂到信号量等待任务队列的队尾。
信号量释放,若没有任务等待该信号量,则直接将计数器加1返回。否则唤醒该信号量等待任务队列上的第一个任务。
信号量删除,将正在使用的信号量置为未使用信号量,并挂回到未使用链表。
信号量允许多个任务在同一时刻访问共享资源,但会限制同一时刻访问此资源的最大任务数目。
当访问资源的任务数达到该资源允许的最大数量时,会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。
使用场景
在多任务系统中,信号量是一种非常灵活的同步方式,可以运用在多种场合中,实现锁、同步、资源计数等功能,
也能方便的用于任务与任务,中断与任务的同步中。信号量常用于协助一组相互竞争的任务访问共享资源。
信号量有三种申请模式:无阻塞模式、永久阻塞模式、定时阻塞模式
无阻塞模式:即任务申请信号量时,入参timeout等于0。若当前信号量计数值不为0,则申请成功,否则立即返回申请失败。
永久阻塞模式:即任务申请信号量时,入参timeout等于0xFFFFFFFF。若当前信号量计数值不为0,则申请成功。
否则该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,直到有其他任务释放该信号量,
阻塞任务才会重新得以执行。
定时阻塞模式:即任务申请信号量时,0<timeout<0xFFFFFFFF。若当前信号量计数值不为0,则申请成功。
否则,该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,
超时前如果有其他任务释放该信号量,则该任务可成功获取信号量继续执行,若超时前未获取到信号量,接口将返回超时错误码。
使用流程
通过make menuconfig配置信号量模块
创建信号量LOS_SemCreate,若要创建二值信号量则调用LOS_BinarySemCreate。
申请信号量LOS_SemPend。
释放信号量LOS_SemPost。
删除信号量LOS_SemDelete。
注意事项
由于中断不能被阻塞,因此不能在中断中使用阻塞模式申请信号量。
******************************************************************************/
#if (LOSCFG_BASE_IPC_SEM == YES)
#if (LOSCFG_BASE_IPC_SEM_LIMIT <= 0)
......
......@@ -36,9 +36,16 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
LITE_OS_SEC_BSS STATIC LOS_ERRORHANDLE_FUNC g_errHandleHook = NULL;
//系统中只有一个错误处理的钩子函数。当多次注册钩子函数时,最后一次注册的钩子函数会覆盖前一次注册的函数。
LITE_OS_SEC_BSS STATIC LOS_ERRORHANDLE_FUNC g_errHandleHook = NULL;//错误接管钩子函数
/******************************************************************************
调用钩子函数,处理错误
fileName:存放错误日志的文件名,系统内部调用时,入参为"os_unspecific_file"
lineNo:发生错误的代码行号系统内部调用时,若值为0xa1b2c3f8,表示未传递行号
errnoNo:错误码
paraLen:入参para的长度系统内部调用时,入参为0
para:错误标签系统内部调用时,入参为NULL
******************************************************************************/
LITE_OS_SEC_TEXT_INIT UINT32 LOS_ErrHandle(CHAR *fileName, UINT32 lineNo, UINT32 errorNo,
UINT32 paraLen, VOID *para)
{
......@@ -48,7 +55,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_ErrHandle(CHAR *fileName, UINT32 lineNo, UINT32
return LOS_OK;
}
//设置钩子函数,处理错误
LITE_OS_SEC_TEXT_INIT VOID LOS_SetErrHandleHook(LOS_ERRORHANDLE_FUNC fun)
{
g_errHandleHook = fun;
......
......@@ -37,6 +37,32 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
基本概念
C++作为目前使用最广泛的编程语言之一,支持类、封装、重载等特性,是在C语言基础上
开发的一种面向对象的编程语言。
运作机制
STL(Standard Template Library)标准模板库,是一些“容器”的集合,也是算法和其他
一些组件的集合。其目的是标准化组件,使用标准化组件后可以不用重新开发,直接使用现成的组件。
开发流程
通过make menuconfig使能C++支持。
使用C++特性之前,需要调用函数LOS_CppSystemInit,初始化C++构造函数。
C函数与C++函数混合调用。在C++中调用C程序的函数,代码需加入C++包含的宏:
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus * /
#endif /* __cplusplus * /
/* code * /
...
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus * /
#endif /* __cplusplus * /
******************************************************************************/
typedef VOID (*InitFunc)(VOID);
......
......@@ -45,33 +45,6 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
基本概念
C++作为目前使用最广泛的编程语言之一,支持类、封装、重载等特性,是在C语言基础上
开发的一种面向对象的编程语言。
运作机制
STL(Standard Template Library)标准模板库,是一些“容器”的集合,也是算法和其他
一些组件的集合。其目的是标准化组件,使用标准化组件后可以不用重新开发,直接使用现成的组件。
开发流程
通过make menuconfig使能C++支持。
使用C++特性之前,需要调用函数LOS_CppSystemInit,初始化C++构造函数。
C函数与C++函数混合调用。在C++中调用C程序的函数,代码需加入C++包含的宏:
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus * /
#endif /* __cplusplus * /
/* code * /
...
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus * /
#endif /* __cplusplus * /
******************************************************************************/
/**
* @ingroup los_cppsupport
* If scatter load is disabled, this flag should be passed as the third parameter when LOS_CppSystemInit() is called.
......
......@@ -45,6 +45,18 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
基本概念
错误处理指程序运行错误时,调用错误处理模块的接口函数,上报错误信息,并调用注册的钩子函数
进行特定处理,保存现场以便定位问题。通过错误处理,可以控制和提示程序中的非法输入,防止程序崩溃。
运作机制
错误处理是一种机制,用于处理异常状况。当程序出现错误时,会显示相应的错误码。
此外,如果注册了相应的错误处理函数,则会执行这个函数。
******************************************************************************/
/**
* @ingroup los_err
* @brief Define the pointer to the error handling function.
......
......@@ -45,6 +45,33 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/******************************************************************************
调用API接口时可能会出现错误,此时接口会返回对应的错误码,以便快速定位错误原因。
错误码是一个32位的无符号整型数,31~24位表示错误等级,23~16位表示错误码标志(当前该标志值为0),
15~8位代表错误码所属模块,7~0位表示错误码序号。
错误码中的错误等级
错误等级 数值 含义
NORMAL 0 提示
WARN 1 告警
ERR 2 严重
FATAL 3 致命
例如
#define LOS_ERRNO_TSK_NO_MEMORY LOS_ERRNO_OS_FATAL(LOS_MOD_TSK, 0x00)
#define LOS_ERRNO_OS_FATAL(MID, ERRNO) \
(LOS_ERRTYPE_FATAL | LOS_ERRNO_OS_ID | ((UINT32)(MID) << 8) | ((UINT32)(ERRNO)))
说明
LOS_ERRTYPE_FATAL:错误等级为FATAL,值为0x03000000 LOS_ERRNO_OS_ID:错误码标志,
值为0x000000 MID:所属模块,LOS_MOD_TSK的值为0x2 ERRNO:错误码序号
所以LOS_ERRNO_TSK_NO_MEMORY的值为0x03000200
错误码接管
有时只靠错误码不能快速准确的定位问题,为方便用户分析错误,错误处理模块支持
注册错误处理的钩子函数,发生错误时,用户可以调用LOS_ErrHandle接口以执行错误处理函数。
******************************************************************************/
/**
* @ingroup los_errno
* OS error code flag.
......
......@@ -54,7 +54,7 @@ extern "C" {
*
* Solution: Configure the maximum number of queue resources to be greater than 0. If queue modules are not used,
* set the configuration item for the tailoring of the maximum number of queue resources to NO.
*/
*/ //系统支持的最大队列数为0
#define LOS_ERRNO_QUEUE_MAXNUM_ZERO LOS_ERRNO_OS_ERROR(LOS_MOD_QUE, 0x00)
/**
......
......@@ -23,15 +23,15 @@
+ [los_tick.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/los_tick.c) -> [鸿蒙内核源码分析(时钟管理篇)](https://blog.csdn.net/kuangyufei/article/details/108603468) -> 是谁在一直触发调度 ? 硬时钟中断都干了些什么事?
+ [los_timeslice.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/los_timeslice.c) -> []() -> 进程和任务能一直占有CPU吗 ? 怎么合理的分配时间 ?
+ [ipc](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/) -> []() -> 进程间通讯有哪些方式 ? 请说出三种 ? 是如何实现的 ?
+ [los_event.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_event.c) -> []() -> 事件解决了什么问题 ? 怎么管理的 ?
+ [los_futex.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_futex.c) -> []() -> futex 是Fast Userspace muTexes的缩写(快速用户空间互斥体),它有什么作用 ?
+ [los_ipcdebug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_ipcdebug.c) -> []() -> 进程间通讯如何调试 ?
+ [los_mux.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_mux.c) -> []() -> 互斥量,有你没我的零和博弈, 为什么需要互斥量 ? 是如何实现的 ?
+ [los_queue.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_queue.c) -> []() -> 内核消息队列是如何实现的 ? 对长度和大小有限制吗 ?
+ [los_queue_debug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_queue_debug.c) -> []() -> 如何调试消息队列 ?
+ [los_sem.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_sem.c) -> []() -> 信号量解决了什么问题 ? 它的本质是什么 ?
+ [los_sem_debug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_sem_debug.c) -> []() -> 如何调试信号量 ?
+ [los_signal.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/ipc/base/los_signal.c) -> []() -> 信号解决了什么问题? 你知道哪些信号 ?
+ [los_event.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_event.c) -> []() -> 事件解决了什么问题 ? 怎么管理的 ?
+ [los_futex.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/base/los_futex.c) -> []() -> futex 是Fast Userspace muTexes的缩写(快速用户空间互斥体),它有什么作用 ?
+ [los_ipcdebug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/base/los_ipcdebug.c) -> []() -> 进程间通讯如何调试 ?
+ [los_mux.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_mux.c) -> []() -> 互斥量,有你没我的零和博弈, 为什么需要互斥量 ? 是如何实现的 ?
+ [los_queue.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_queue.c) -> []() -> 内核消息队列是如何实现的 ? 对长度和大小有限制吗 ?
+ [los_queue_debug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_queue_debug.c) -> []() -> 如何调试消息队列 ?
+ [los_sem.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_sem.c) -> []() -> 信号量解决了什么问题 ? 它的本质是什么 ?
+ [los_sem_debug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_sem_debug.c) -> []() -> 如何调试信号量 ?
+ [los_signal.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_signal.c) -> []() -> 信号解决了什么问题? 你知道哪些信号 ?
+ [mem](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/) -> []() ->
+ [misc](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/) -> []() ->
+ [kill_shellcmd.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/kill_shellcmd.c) -> []() -> shell命令kill的实现,熟悉的 kill 9 18 的背后发生了什么?
......
git add -A
git commit -m '2021年首次注解提交,规范注解格式,对自旋锁,双向链表,时钟,位图模块注解.
git commit -m '规范和补充中断,定时器,互斥量,信号量模块注解.
搜索 @note_pic 方便理解画的字符图
搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善
搜索 @note_thinking 一点思考和吐槽的地方
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册