提交 685e1c3a 编写于 作者: D duangavin123

纯净版

Signed-off-by: Nduangavin123 <duanxichao@huawei.com>
上级 5acaf492
......@@ -30,9 +30,6 @@ OpenHarmony也提供了一系列可选的系统组件,方便设备开发者按
## 文档导读<a name="section19810171681218"></a>
- [轻量和小型系统开发指导](#table3762949121211)
- [标准系统开发指导](#table17667535516)
**表 1** 轻量和小型系统开发指导(参考内存<128MB)
| 学习路径 | 开发者业务 | 相关文档 |
......@@ -42,7 +39,7 @@ OpenHarmony也提供了一系列可选的系统组件,方便设备开发者按
| 快速入门 | 快速熟悉OpenHarmony环境搭建、编译、烧录、调测、运行。 | [轻量和小型系统快速入门](quick-start/quickstart-lite.md) |
| 基础能力使用 | 使用OpenHarmony提供的基础能力 | -&nbsp;[轻量系统内核开发指南](kernel/kernel-mini-overview.md)<br/>-&nbsp;[小型系统内核开发指南](kernel/kernel-small-overview.md)<br/>-&nbsp;[驱动开发指南](driver/driver-hdf-overview.md)<br/>-&nbsp;[子系统开发指南](subsystems/subsys-build-mini-lite.md)<br/>-&nbsp;[安全指南](security/security-guidelines-overall.md)<br/>-&nbsp;[隐私保护](security/security-privacy-protection.md) |
| 进阶开发 | 结合系统能力开发智能设备 | -&nbsp;[WLAN连接类产品](guide/device-wlan-led-control.md)<br/>-&nbsp;[无屏摄像头类产品](guide/device-iotcamera-control-overview.md)<br/>-&nbsp;[带屏摄像头类产品](guide/device-camera-control-overview.md) |
| 移植适配 | -&nbsp;针对特定芯片做移植适配<br/>-&nbsp;对三方库进行移植适配 | -&nbsp;[轻量系统芯片移植指导](porting/oem_transplant_chip_prepare_knows.md)<br/>-&nbsp;[小型系统芯片移植指导](porting/porting-smallchip-prepare-needs.md)<br/>-&nbsp;[轻量和小型系统三方库移植指导](porting/porting-thirdparty-overview.md) |
| 移植适配 | -&nbsp;针对特定芯片做移植适配<br/>-&nbsp;对三方库进行移植适配 | -&nbsp;[轻量系统芯片移植指导](porting/porting-minichip.md)<br/>-&nbsp;[小型系统芯片移植指导](porting/porting-smallchip-prepare-needs.md)<br/>-&nbsp;[轻量和小型系统三方库移植指导](porting/porting-thirdparty-overview.md) |
| 贡献组件 | 为OpenHarmony贡献功能组件 | -&nbsp;[HPM&nbsp;Part&nbsp;介绍](hpm-part/hpm-part-about.md)<br/>-&nbsp;[HPM&nbsp;Part&nbsp;开发指导](hpm-part/hpm-part-development.md)<br/>-&nbsp;[HPM&nbsp;Part&nbsp;参考](hpm-part/hpm-part-reference.md) |
| 参考 | 开发参考 | -&nbsp;[API参考](https://gitee.com/link?target=https%3A%2F%2Fdevice.harmonyos.com%2Fcn%2Fdocs%2Fdevelop%2Fapiref%2Fjs-framework-file-0000000000611396)<br/>-&nbsp;[常见问题](faqs/faqs-overview.md) |
......
# DAC
- [概述](#1)
- [功能简介](#2)
- [基本概念](#3)
- [运作机制](#4)
- [约束与限制](#5)
- [开发指导](#6)
- [场景介绍](#7)
- [接口说明](#8)
- [开发步骤](#9)
## 概述
## 概述<a name="1"></a>
### 功能简介<a name="2"></a>
### 功能简介
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备 。
### 基本概念<a name="3"></a>
### 基本概念
DAC模块支持数模转换的开发。它主要用于:
......@@ -39,33 +29,32 @@ DAC模块支持数模转换的开发。它主要用于:
最低有效位LSB(Least Significant Byte),指的是一个二进制数字中的第0位(即最低位)。
### 运作机制<a name="4"></a>
### 运作机制
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。DAC模块接口适配模式采用统一服务模式([如图1](#fig14423182615525)所示)。
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。DAC模块接口适配模式采用统一服务模式(如图1所示)。
DAC模块各分层的作用为:接口层提供打开设备,写入数据,关闭设备接口的能力。核心层主要提供绑定设备、初始化设备以及释放设备的能力。适配层实现其他具体的功能。
![](../public_sys-resources/icon-note.gif) 说明:核心层可以调用接口层的函数,也可以通过钩子函数调用适配层函数,从而使得适配层间接的可以调用接口层函数,但是不可逆转接口层调用适配层函数。
**图 1** 统一服务模式<a name="fig14423182615525"></a>
**图 1** 统一服务模式
![](figures/统一服务模式结构图.png "DAC统一服务模式")
### 约束与限制
### 约束与限制<a name="5"></a>
DAC模块当前仅支持轻量和小型系统内核(LiteOS) 。
DAC模块当前仅支持轻量和小型系统内核(LiteOS)。
## 开发指导<a name="6"></a>
## 开发指导
### 场景介绍<a name="7"></a>
### 场景介绍
DAC模块主要在设备中数模转换,音频输出,电机控制等设备使用,设置将DAC模块传入的数字信号转换为输出模拟信号时需要用到DAC数模转换驱动。
### 接口说明<a name="8"></a>
### 接口说明
通过以下DacMethod中的函数调用DAC驱动对应的函数。
......@@ -84,7 +73,7 @@ struct DacMethod {
**表 1** DacMethod结构体成员的回调函数功能说明
<a name="table27410339187"></a>
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| -------- | ------------------------------------------------------------ | ---- | ------------------ | -------------- |
......@@ -94,7 +83,7 @@ struct DacMethod {
### 开发步骤<a name="9"></a>
### 开发步骤
DAC模块适配包含以下四个步骤:
......@@ -132,7 +121,7 @@ DAC模块适配包含以下四个步骤:
| policy | 具体配置为0,不发布服务|
| priority | 驱动启动优先级(0-200),值越大优先级越低,,优先级相同则不保证device的加载顺序。|
| permission | 驱动权限|
| moduleName | 固定为 HDF_PLATFORM_DAC_MANAGER|
| moduleName | 固定为HDF_PLATFORM_DAC_MANAGER|
| serviceName | 固定为HDF_PLATFORM_DAC_MANAGER|
| deviceMatchAttr | 没有使用,可忽略|
......@@ -293,7 +282,7 @@ DAC模块适配包含以下四个步骤:
```
![](../public_sys-resources/icon-note.gif) **说明:**
DacDevice成员DacMethod的定义和成员说明见[接口说明](#section752964871810)。
DacDevice成员DacMethod的定义和成员说明见[接口说明](#接口说明)。
- Init函数参考
......@@ -304,7 +293,7 @@ DAC模块适配包含以下四个步骤:
返回值:
HDF_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。
| 状态(值) | 问题描述 |
| ---------------------- | -------------- |
......
......@@ -20,11 +20,12 @@ PIN是一个软件层面的概念,目的是为了统一各SoC厂商PIN管脚
### 运作机制
在HDF框架中,PIN模块暂不支持用户态,所以不需要发布服务,接口适配模式采用无服务模式(如[图1](#无服务模式结构图)所示),用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
在HDF框架中,PIN模块暂不支持用户态,所以不需要发布服务,接口适配模式采用无服务模式(如图1所示),用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
PIN模块各分层作用:接口层提供获取PIN管脚、设置PIN管脚推拉方式、获取PIN管脚推拉方式、设置PIN管脚推拉强度、获取PIN管脚推拉强度、设置PIN管脚功能、获取PIN管脚功能、释放PIN管脚的接口。核心层主要提供PIN管脚资源匹配,PIN管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互。适配层主要是将钩子函数的功能实例化,实现具体的功能。
**图 1** 无服务模式结构图
![无服务模式结构图](figures/无服务模式结构图.png)
### 约束与限制
......
# 外设驱动开发示例<a name="ZH-CN_TOPIC_0000001157063303"></a>
- [概述](#section86753818426)
- [硬件资源简介](#section123071189431)
- [Input模型简介](#section53684425430)
- [环境搭建](#section661075474418)
- [TouchScreen器件驱动开发](#section15233162984520)
- [配置设备描述信息](#section16761205604515)
- [配置Touchscreen器件信息](#section156331030144617)
- [适配器件私有驱动](#section17127331595)
- [编译及烧录](#section16465031164711)
- [调试验证](#section62577313482)
- [Input模型工作流程解析](#section1578569154917)
- [私有配置信息解析](#section1310113815495)
- [管理驱动层初始化及注册驱动至HDF框架](#section614512119500)
- [公共驱动层初始化及注册驱动至HDF框架](#section16194201755019)
- [器件驱动层初始化及注册驱动至HDF框架](#section1090743312505)
- [具体调用逻辑串联函数](#section81801147529)
## 概述<a name="section86753818426"></a>
......@@ -40,7 +21,7 @@ Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动
此外,Input模型预先实现了数据通道以及设备配置信息解析等函数。
关于Input模型的详细介绍请参考《[Touchscreen开发概述](../driver/driver-peripherals-touch-des.md#section175431838101617)》。
关于Input模型的详细介绍请参考《[Touchscreen开发概述](../driver/driver-peripherals-touch-des.md#概述)》。
## 环境搭建<a name="section661075474418"></a>
......
......@@ -34,8 +34,7 @@
- [LMS调测](kernel-mini-memory-lms.md)
- 附录
- [内核编码规范](kernel-mini-appx-code.md)
- 基本数据结构
- [双向链表](kernel-mini-appx-data-list.md)
- [基本数据结构](kernel-mini-appx-data-list.md)
- 标准库支持
- [CMSIS支持](kernel-mini-appx-lib-cmsis.md)
- [POSIX支持](kernel-mini-appx-lib-posix.md)
......@@ -148,11 +147,10 @@
- [tftp](kernel-small-debug-shell-net-tftp.md)
- [魔法键使用方法](kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel-small-debug-shell-error.md)
- [Trace](kernel-small-debug-trace.md)
- [Trace调测](kernel-small-debug-trace.md)
- [Perf调测](kernel-mini-memory-perf.md)
- [LMS调测](kernel-small-memory-lms.md)
- 进程调测
- [CPU占用率](kernel-small-debug-process-cpu.md)
- [进程调测](kernel-small-debug-process-cpu.md)
- 内核态内存调测
- [内存信息统计](kernel-small-debug-memory-info.md)
- [内存泄漏检测](kernel-small-debug-memory-leak.md)
......@@ -165,10 +163,10 @@
- 使用说明
- [接口调用方式](kernel-small-debug-user-guide-use-api.md)
- [命令行参数方式](kernel-small-debug-user-guide-use-cli.md)
- [常见问题场景](kernel-small-debug-user-faqs.md)
- [常见问题](kernel-small-debug-user-faqs.md)
- 其他内核调测手段
- [临终遗言](kernel-small-debug-trace-other-lastwords.md)
- [常见问题定位方法](kernel-small-debug-trace-other-faqs.md)
- [常见问题](kernel-small-debug-trace-other-faqs.md)
- 附录
- 基本数据结构
- [双向链表](kernel-small-apx-dll.md)
......@@ -176,11 +174,10 @@
- [标准库](kernel-small-apx-library.md)
- 标准系统内核
- [Linux内核概述](kernel-standard-overview.md)
- [开发板Patch使用指导](kernel-standard-patch.md)
- [OpenHarmony开发板Patch使用指导](kernel-standard-patch.md)
- [Linux内核编译与构建指导](kernel-standard-build.md)
- [内核增强特性](kernel-standard-enhanced-features.md)
- [内存管理](kernel-standard-mm.md)
- [Enhanced SWAP特性介绍](kernel-standard-mm-eswap.md)
- [任务调度](kernel-standard-sched.md)
- [关联线程组调度](kernel-standard-sched-rtg.md)
- [CPU轻量级隔离](kernel-standard-sched-cpuisolation.md)
- [Enhanced SWAP特性介绍](kernel-standard-mm-eswap.md)
- [任务调度](kernel-standard-sched.md)
- [关联线程组调度](kernel-standard-sched-rtg.md)
- [CPU轻量级隔离](kernel-standard-sched-cpuisolation.md)
# 时间管理
## 基本概念
时间管理以系统时钟为基础,给应用程序提供所有和时间有关的服务。
......@@ -24,20 +25,22 @@ OpenHarmony LiteOS-M内核时间管理模块提供时间转换、统计功能。
OpenHarmony LiteOS-M内核的时间管理提供下面几种功能,接口详细信息可以查看API参考。
**表1** 时间管理接口
**表1** 时间转换
| 接口名 | 描述 |
| -------- | -------- |
| LOS_MS2Tick | 毫秒转换成Tick |
| LOS_Tick2MS | Tick转化为毫秒 |
| OsCpuTick2MS | Cycle数目转化为毫秒,使用2个UINT32类型的数值分别表示结果数值的高、低32位。 |
| OsCpuTick2US | Cycle数目转化为微秒,使用2个UINT32类型的数值分别表示结果数值的高、低32位。 |
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 时间转换 | LOS_MS2Tick | 毫秒转换成Tick |
| | LOS_Tick2MS | Tick转化为毫秒 |
| | OsCpuTick2MS | Cycle数目转化为毫秒,使用2个UINT32类型的数值分别表示结果数值的高、低32位。 |
| | OsCpuTick2US | Cycle数目转化为微秒,使用2个UINT32类型的数值分别表示结果数值的高、低32位。 |
| 时间统计 | LOS_SysClockGet | 获取系统时钟 |
| | LOS_TickCountGet | 获取自系统启动以来的Tick数 |
| | LOS_CyclePerTickGet | 获取每个Tick多少Cycle数 |
| | LOS_CurrNanosec |获取自系统启动以来的纳秒数|
| 延时管理 | LOS_UDelay |以us为单位的忙等,但可以被优先级更高的任务抢占|
| | LOS_MDelay |以ms为单位的忙等,但可以被优先级更高的任务抢占|
**表2** 时间统计
| 接口名 | 描述 |
| -------- | -------- |
| LOS_SysClockGet | 获取系统时钟 |
| LOS_TickCountGet | 获取自系统启动以来的Tick数 |
| LOS_CyclePerTickGet | 获取每个Tick多少Cycle数 |
## 开发流程
......@@ -78,6 +81,7 @@ OpenHarmony LiteOS-M内核的时间管理提供下面几种功能,接口详细
时间转换:
```
VOID Example_TransformTime(VOID)
{
......@@ -93,6 +97,7 @@ VOID Example_TransformTime(VOID)
时间统计和时间延迟:
```
VOID Example_GetTime(VOID)
{
......@@ -124,6 +129,7 @@ VOID Example_GetTime(VOID)
时间转换:
```
tick = 1000
ms = 1000
......@@ -131,6 +137,7 @@ ms = 1000
时间统计和时间延迟:
```
LOS_CyclePerTickGet = 495000
LOS_TickCountGet = 1
......
# 附录
- **[内核编码规范](kernel-mini-appx-code.md)**
- **[基本数据结构](kernel-mini-appx-data.md)**
- **[基本数据结构](kernel-mini-appx-data-list.md)**
- **[标准库支持](kernel-mini-appx-lib.md)**
\ No newline at end of file
# 内核编码规范
- [总体原则](#总体原则)
- [目录结构](#目录结构)
- [命名](#命名)
- [注释](#注释)
- [格式](#格式)
- [](#宏)
- [头文件](#头文件)
- [数据类型](#数据类型)
- [变量](#变量)
- [断言](#断言)
- [函数](#函数)
此规范基于业界通用的编程规范整理而成,请内核的开发人员遵守这样的编程风格。
......@@ -41,7 +30,7 @@
推荐使用驼峰风格,具体规则如下:
| 类型 | 命名风格 | 形式 |
| 类型 | 命名风格 | 形式 |
| -------- | -------- | -------- |
| 函数、结构体类型、枚举类型、联合体类型、typedef的类型 | 大驼峰,或带有模块前缀的大驼峰 | AaaBbb<br/>XXX_AaaBbb |
| 局部变量,函数参数,宏参数,结构体中字段,联合体中成员 | 小驼峰 | aaaBBB |
......@@ -52,6 +41,7 @@
内核对外API建议采用LOS_ModuleFunc的形式,如果有宾语则建议采用前置的方式,比如:
```
LOS_TaskCreate
LOS_MuxLock
......@@ -59,6 +49,7 @@ LOS_MuxLock
kernel目录下内部模块间的接口使用OsModuleFunc的形式,比如:
```
OsTaskScan
OsMuxInit
......@@ -77,6 +68,7 @@ OsMuxInit
注释风格要统一,建议优先选择/\* \*/的方式,注释符与注释内容之间要有1空格,单行、多行注释风格如下:
```
/* 单行注释 */
// 单行注释
......@@ -96,6 +88,7 @@ OsMuxInit
建议将多条连续的右侧注释对齐,比如:
```
#define CONST_A 100 /* Const A */
#define CONST_B 2000 /* Const B */
......@@ -112,6 +105,7 @@ OsMuxInit
比如:
```
struct MyType { // 跟随语句放行末,前置1空格
...
......@@ -129,6 +123,7 @@ int Foo(int a) { // 函数左大括号独占一行,放行首
每行字符数不要超过 120 个,代码过长时应当换行,换行时将操作符留在行末,新行缩进一层或进行同类对齐,并将表示未结束的操作符或连接符号留在行末。
```
// 假设下面第一行已经不满足行宽要求
if (currentValue > MIN && // Good:换行后,布尔操作符放在行末
......@@ -156,6 +151,7 @@ int result = DealWithStructLikeParams(left.x, left.y, // 表示一组相关
包括 if/for/while/do-while 语句应使用大括号,即复合语句。
```
while (condition) {} // Good:即使循环体是空,也应使用大括号
while (condition) {
......@@ -165,6 +161,7 @@ while (condition) {
case/default 语句相对 switch 缩进一层,风格如下:
```
switch (var) {
case 0: // Good: 缩进
......@@ -181,6 +178,7 @@ switch (var) {
指针类型"\*"跟随变量或者函数名,例如:
```
int *p1; // OK
int* p2; // Bad:跟随类型
......@@ -200,6 +198,7 @@ sz = sizeof(int*); // OK:右侧没有变量,"*"跟随类型
定义宏时,要使用完备的括号,例如:
```
#define SUM(a, b) ((a) + (b)) // 符合本规范要求.
#define SOME_CONST 100 // Good: 单独的数字无需括号
......@@ -217,6 +216,7 @@ sz = sizeof(int*); // OK:右侧没有变量,"*"跟随类型
- 宏参数作为独立部分,在逗号表达式,函数或宏调用列表中,可以不加括号。
```
// x 不要加括号
#define MAKE_STR(x) #x
......
# 双向链表
# 基本数据结构
- [基本概念](#基本概念)
- [功能说明](#功能说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -19,22 +12,16 @@
双向链表模块为用户提供下面几种功能,接口详细信息可以查看API参考。
| **功能分类** | **接口名** | **描述** |
| -------- | -------- | -------- |
| 初始化链表 | LOS_ListInit | 将指定双向链表节点初始化为双向链表 |
| | LOS_DL_LIST_HEAD | 定义一个双向链表节点并以该节点初始化为双向链表 |
| 增加节点 | LOS_ListAdd | 将指定节点插入到双向链表头端 |
| | LOS_ListTailInsert | 将指定节点插入到双向链表尾端 |
| 删除节点 | LOS_ListDelete | 将指定节点从链表中删除 |
| | LOS_ListDelInit | 将指定节点从链表中删除,并使用该节点初始化链表 |
| 判断双向链表是否为空 | LOS_ListEmpty | 判断链表是否为空 |
| 获取结构体信息 | LOS_DL_LIST_ENTRY | 获取包含链表的结构体地址,接口的第一个入参表示的是链表中的某个节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称 |
| | LOS_OFF_SET_OF | 获取指定结构体内的成员相对于结构体起始地址的偏移量 |
| 遍历双向链表 | LOS_DL_LIST_FOR_EACH | 遍历双向链表 |
| | LOS_DL_LIST_FOR_EACH_SAFE | 遍历双向链表,并存储当前节点的后继节点用于安全校验 |
| 遍历包含双向链表的结构体 | LOS_DL_LIST_FOR_EACH_ENTRY | 遍历指定双向链表,获取包含该链表节点的结构体地址 |
| | LOS_DL_LIST_FOR_EACH_ENTRY_SAFE | 遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址 |
| | |
| -------- | -------- |
| **功能分类** | **接口描述** |
| 初始化链表 | -&nbsp;LOS_ListInit:将指定双向链表节点初始化为双向链表<br/>-&nbsp;LOS_DL_LIST_HEAD:定义一个双向链表节点并以该节点初始化为双向链表 |
| 增加节点 | -&nbsp;LOS_ListAdd:将指定节点插入到双向链表头端<br/>-&nbsp;LOS_ListTailInsert:将指定节点插入到双向链表尾端 |
| 删除节点 | -&nbsp;LOS_ListDelete:将指定节点从链表中删除<br/>-&nbsp;LOS_ListDelInit:将指定节点从链表中删除,并使用该节点初始化链表 |
| 判断双向链表是否为空 | LOS_ListEmpty:判断链表是否为空 |
| 获取结构体信息 | -&nbsp;LOS_DL_LIST_ENTRY:获取包含链表的结构体地址,接口的第一个入参表示的是链表中的某个节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称<br/>-&nbsp;LOS_OFF_SET_OF:获取指定结构体内的成员相对于结构体起始地址的偏移量 |
| 遍历双向链表 | -&nbsp;LOS_DL_LIST_FOR_EACH:遍历双向链表<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_SAFE:遍历双向链表,并存储当前节点的后继节点用于安全校验 |
| 遍历包含双向链表的结构体 | -&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY:遍历指定双向链表,获取包含该链表节点的结构体地址<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY_SAFE:遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址 |
## 开发流程
......@@ -82,6 +69,7 @@
示例代码如下:
```
#include "stdio.h"
#include "los_list.h"
......@@ -125,8 +113,10 @@ static UINT32 ListSample(VOID)
编译运行得到的结果为:
```
Initial head Add listNode1 success
Initial head
Add listNode1 success
Tail insert listNode2 success
Delete success
```
# CMSIS支持
- [基本概念](#基本概念)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -18,90 +13,135 @@
CMSIS-RTOS v2提供下面几种功能,接口详细信息可以查看API参考。
**表1** CMSIS-RTOS v2接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 内核信息与控制 | osKernelGetInfo | 获取RTOS内核信息。 |
| | osKernelGetState | 获取当前的RTOS内核状态。 |
| | osKernelGetSysTimerCount | 获取RTOS内核系统计时器计数。 |
| | osKernelGetSysTimerFreq | 获取RTOS内核系统计时器频率。 |
| | osKernelInitialize | 初始化RTOS内核。 |
| | osKernelLock | 锁定RTOS内核调度程序。 |
| | osKernelUnlock | 解锁RTOS内核调度程序。 |
| | osKernelRestoreLock | 恢复RTOS内核调度程序锁定状态。 |
| | osKernelResume | 恢复RTOS内核调度程序。(暂未实现) |
| | osKernelStart | 启动RTOS内核调度程序。 |
| | osKernelSuspend | 挂起RTOS内核调度程序。(暂未实现) |
| | osKernelGetTickCount | 获取RTOS内核滴答计数。 |
| | osKernelGetTickFreq | 获取RTOS内核滴答频率。 |
| 线程管理 | osThreadDetach | 分离线程(线程终止时可以回收线程存储)。 |
| | osThreadEnumerate | 枚举活动线程。(暂未实现) |
| | osThreadExit | 终止当前正在运行的线程的执行。 |
| | osThreadGetCount | 获取活动线程的数量。 |
| | osThreadGetId | 返回当前正在运行的线程的线程ID。 |
| | osThreadGetName | 获取线程的名称。 |
| | osThreadGetPriority | 获取线程的当前优先级。 |
| | osThreadGetStackSize | 获取线程的堆栈大小。 |
| | osThreadGetStackSpace | 根据执行期间的堆栈水印记录获取线程的可用堆栈空间。 |
| | osThreadGetState | 获取线程的当前线程状态。 |
| | osThreadJoin | 等待指定线程终止。 |
| | osThreadNew | 创建一个线程并将其添加到活动线程中。 |
| | osThreadResume | 恢复线程的执行。 |
| | osThreadSetPriority | 更改线程的优先级。 |
| | osThreadSuspend | 暂停执行线程。 |
| | osThreadTerminate | 终止线程的执行。 |
| | osThreadYield | 将控制权传递给处于就绪状态的下一个线程。 |
| 线程标志 | osThreadFlagsSet | 设置线程的指定线程标志。 |
| | osThreadFlagsClear | 清除当前正在运行的线程的指定线程标志。 |
| | osThreadFlagsGet | 获取当前正在运行的线程的当前线程标志。 |
| | osThreadFlagsWait | 等待当前正在运行的线程的一个或多个线程标志发出信号。 |
| 事件标志 | osEventFlagsGetName | 获取事件标志对象的名称。(暂未实现) |
| | osEventFlagsNew | 创建并初始化事件标志对象。 |
| | osEventFlagsDelete | 删除事件标志对象。 |
| | osEventFlagsSet | 设置指定的事件标志。 |
| | osEventFlagsClear | 清除指定的事件标志。 |
| | osEventFlagsGet | 获取当前事件标志。 |
| | osEventFlagsWait | 等待一个或多个事件标志被发出信号。 |
| 通用等待函数 | osDelay | 等待超时(时间延迟)。 |
| | osDelayUntil | 等到指定时间。 |
| 计时器管理 | osTimerDelete | 删除计时器。 |
| | osTimerGetName | 获取计时器的名称。(暂未实现) |
| | osTimerIsRunning | 检查计时器是否正在运行。 |
| | osTimerNew | 创建和初始化计时器。 |
| | osTimerStart | 启动或重新启动计时器。 |
| | osTimerStop | 停止计时器。 |
| 互斥管理 | osMutexAcquire | 获取互斥或超时(如果已锁定)。 |
| | osMutexDelete | 删除互斥对象。 |
| | osMutexGetName | 获取互斥对象的名称。(暂未实现) |
| | osMutexGetOwner | 获取拥有互斥对象的线程。 |
| | osMutexNew | 创建并初始化Mutex对象。 |
| | osMutexRelease | 释放由osMutexAcquire获取的Mutex。 |
| 信号量 | osSemaphoreAcquire | 获取信号量令牌或超时(如果没有可用的令牌)。 |
| | osSemaphoreDelete | 删除一个信号量对象。 |
| | osSemaphoreGetCount | 获取当前信号量令牌计数。 |
| | osSemaphoreGetName | 获取信号量对象的名称。(暂未实现) |
| | osSemaphoreNew | 创建并初始化一个信号量对象。 |
| | osSemaphoreRelease | 释放信号量令牌,直到初始最大计数。 |
| 内存池 | osMemoryPoolAlloc | 从内存池分配一个内存块。 |
| | osMemoryPoolDelete | 删除内存池对象。 |
| | osMemoryPoolFree | 将分配的内存块返回到内存池。 |
| | osMemoryPoolGetBlockSize | 获取内存池中的内存块大小。 |
| | osMemoryPoolGetCapacity | 获取内存池中最大的内存块数。 |
| | osMemoryPoolGetCount | 获取内存池中使用的内存块数。 |
| | osMemoryPoolGetName | 获取内存池对象的名称。 |
| | osMemoryPoolGetSpace | 获取内存池中可用的内存块数。 |
| | osMemoryPoolNew | 创建并初始化一个内存池对象。 |
| 消息队列 | osMessageQueueDelete | 删除消息队列对象。 |
| | osMessageQueueGet | 从队列获取消息,或者如果队列为空,则从超时获取消息。 |
| | osMessageQueueGetCapacity | 获取消息队列中的最大消息数。 |
| | osMessageQueueGetCount | 获取消息队列中排队的消息数。 |
| | osMessageQueueGetMsgSize | 获取内存池中的最大消息大小。 |
| | osMessageQueueGetName | 获取消息队列对象的名称。(暂未实现) |
| | osMessageQueueGetSpace | 获取消息队列中消息的可用插槽数。 |
| | osMessageQueueNew | 创建和初始化消息队列对象。 |
| | osMessageQueuePut | 如果队列已满,则将消息放入队列或超时。 |
| | osMessageQueueReset | 将消息队列重置为初始空状态。(暂未实现) |
**表1** 内核信息与控制
| 接口名 | 接口描述 |
| -------- | -------- |
| osKernelGetInfo | 获取RTOS内核信息。 |
| osKernelGetState | 获取当前的RTOS内核状态。 |
| osKernelGetSysTimerCount | 获取RTOS内核系统计时器计数。 |
| osKernelGetSysTimerFreq | 获取RTOS内核系统计时器频率。 |
| osKernelInitialize | 初始化RTOS内核。 |
| osKernelLock | 锁定RTOS内核调度程序。 |
| osKernelUnlock | 解锁RTOS内核调度程序。 |
| osKernelRestoreLock | 恢复RTOS内核调度程序锁定状态。 |
| osKernelResume | 恢复RTOS内核调度程序。(暂未实现) |
| osKernelStart | 启动RTOS内核调度程序。 |
| osKernelSuspend | 挂起RTOS内核调度程序。(暂未实现) |
| osKernelGetTickCount | 获取RTOS内核滴答计数。 |
| osKernelGetTickFreq | 获取RTOS内核滴答频率。 |
**表2** 线程管理
| 接口名 | 接口描述 |
| -------- | -------- |
| osThreadDetach | 分离线程(线程终止时可以回收线程存储)。(暂未实现) |
| osThreadEnumerate | 枚举活动线程。(暂未实现) |
| osThreadExit | 终止当前正在运行的线程的执行。 |
| osThreadGetCount | 获取活动线程的数量。 |
| osThreadGetId | 返回当前正在运行的线程的线程ID。 |
| osThreadGetName | 获取线程的名称。 |
| osThreadGetPriority | 获取线程的当前优先级。 |
| osThreadGetStackSize | 获取线程的堆栈大小。 |
| osThreadGetStackSpace | 根据执行期间的堆栈水印记录获取线程的可用堆栈空间。 |
| osThreadGetState | 获取线程的当前线程状态。 |
| osThreadJoin | 等待指定线程终止。(暂未实现) |
| osThreadNew | 创建一个线程并将其添加到活动线程中。 |
| osThreadResume | 恢复线程的执行。 |
| osThreadSetPriority | 更改线程的优先级。 |
| osThreadSuspend | 暂停执行线程。 |
| osThreadTerminate | 终止线程的执行。 |
| osThreadYield | 将控制权传递给处于就绪状态的下一个线程。 |
**表3** 线程标志
| 接口名 | 接口描述 |
| -------- | -------- |
| osThreadFlagsSet | 设置线程的指定线程标志。(暂未实现) |
| osThreadFlagsClear | 清除当前正在运行的线程的指定线程标志。(暂未实现) |
| osThreadFlagsGet | 获取当前正在运行的线程的当前线程标志。(暂未实现) |
| osThreadFlagsWait | 等待当前正在运行的线程的一个或多个线程标志发出信号。(暂未实现) |
**表4** 事件标志
| 接口名 | 接口描述 |
| -------- | -------- |
| osEventFlagsGetName | 获取事件标志对象的名称。(暂未实现) |
| osEventFlagsNew | 创建并初始化事件标志对象。 |
| osEventFlagsDelete | 删除事件标志对象。 |
| osEventFlagsSet | 设置指定的事件标志。 |
| osEventFlagsClear | 清除指定的事件标志。 |
| osEventFlagsGet | 获取当前事件标志。 |
| osEventFlagsWait | 等待一个或多个事件标志被发出信号。 |
**表5** 通用等待函数
| 接口名 | 接口描述 |
| -------- | -------- |
| osDelay | 等待超时(时间延迟)。 |
| osDelayUntil | 等到指定时间。 |
**表6** 计时器管理
| 接口名 | 接口描述 |
| -------- | -------- |
| osTimerDelete | 删除计时器。 |
| osTimerGetName | 获取计时器的名称。(暂未实现) |
| osTimerIsRunning | 检查计时器是否正在运行。 |
| osTimerNew | 创建和初始化计时器。 |
| osTimerStart | 启动或重新启动计时器。 |
| osTimerStop | 停止计时器。 |
**表7** 互斥管理
| 接口名 | 接口描述 |
| -------- | -------- |
| osMutexAcquire | 获取互斥或超时(如果已锁定)。 |
| osMutexDelete | 删除互斥对象。 |
| osMutexGetName | 获取互斥对象的名称。(暂未实现) |
| osMutexGetOwner | 获取拥有互斥对象的线程。 |
| osMutexNew | 创建并初始化Mutex对象。 |
| osMutexRelease | 释放由osMutexAcquire获取的Mutex。 |
**表8** 信号量
| 接口名 | 接口描述 |
| -------- | -------- |
| osSemaphoreAcquire | 获取信号量令牌或超时(如果没有可用的令牌)。 |
| osSemaphoreDelete | 删除一个信号量对象。 |
| osSemaphoreGetCount | 获取当前信号量令牌计数。 |
| osSemaphoreGetName | 获取信号量对象的名称。(暂未实现) |
| osSemaphoreNew | 创建并初始化一个信号量对象。 |
| osSemaphoreRelease | 释放信号量令牌,直到初始最大计数。 |
**表9** 内存池
| 接口名 | 接口描述 |
| -------- | -------- |
| osMemoryPoolAlloc | 从内存池分配一个内存块。 |
| osMemoryPoolDelete | 删除内存池对象。 |
| osMemoryPoolFree | 将分配的内存块返回到内存池。 |
| osMemoryPoolGetBlockSize | 获取内存池中的内存块大小。 |
| osMemoryPoolGetCapacity | 获取内存池中最大的内存块数。 |
| osMemoryPoolGetCount | 获取内存池中使用的内存块数。 |
| osMemoryPoolGetName | 获取内存池对象的名称。 |
| osMemoryPoolGetSpace | 获取内存池中可用的内存块数。 |
| osMemoryPoolNew | 创建并初始化一个内存池对象。 |
**表10** 消息队列
| 接口名 | 接口描述 |
| -------- | -------- |
| osMessageQueueDelete | 删除消息队列对象。 |
| osMessageQueueGet | 从队列获取消息,或者如果队列为空,则从超时获取消息。 |
| osMessageQueueGetCapacity | 获取消息队列中的最大消息数。 |
| osMessageQueueGetCount | 获取消息队列中排队的消息数。 |
| osMessageQueueGetMsgSize | 获取内存池中的最大消息大小。 |
| osMessageQueueGetName | 获取消息队列对象的名称。(暂未实现) |
| osMessageQueueGetSpace | 获取消息队列中消息的可用插槽数。 |
| osMessageQueueNew | 创建和初始化消息队列对象。 |
| osMessageQueuePut | 如果队列已满,则将消息放入队列或超时。 |
| osMessageQueueReset | 将消息队列重置为初始空状态。(暂未实现) |
### 开发流程
......@@ -115,6 +155,7 @@ CMSIS-RTOS2组件可以作为库或源代码提供(下图显示了库)。通
### 编程实例
```
#include ...
#include "cmsis_os2.h"
......
# 标准库支持
- **[CMSIS支持](kernel-mini-appx-lib-cmsis.md)**
- **[POSIX支持](kernel-mini-appx-lib-posix.md)**
\ No newline at end of file
# 中断管理
- [基本概念](#基本概念)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 基本概念
......@@ -40,27 +35,29 @@
OpenHarmony LiteOS-M内核的中断模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** 中断模块接口
**表1** 创建、删除中断
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 创建、删除中断 | LOS_HwiCreate | 中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序。 |
| | LOS_HwiDelete | 根据指定的中断号,删除中断。 |
| 打开、关闭中断 | LOS_IntUnLock | 开中断,使能当前处理器所有中断响应。 |
| | LOS_IntLock | 关中断,关闭当前处理器所有中断响应。 |
| | LOS_IntRestore | 恢复到使用LOS_IntLock、LOS_IntUnLock操作之前的中断状态。 |
| 使能和屏蔽指定中断 | LOS_HwiDisable | 中断屏蔽。(通过设置寄存器,禁止CPU响应该中断) |
| | LOS_HwiEnable | 中断使能。(通过设置寄存器,允许CPU响应该中断) |
| 设置中断优先级 | LOS_HwiSetPriority | 设置中断优先级。 |
| 触发中断 | LOS_HwiTrigger | 触发中断。(通过写中断控制器的相关寄存器模拟外部中断) |
| 清除中断寄存器状态 | LOS_HwiClear | 清除中断号对应的中断寄存器的状态位,此接口依赖中断控制器版本,非必需。 |
| 接口名 | 描述 |
| -------- | -------- |
| HalHwiCreate | 中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序。 |
| HalHwiDelete | 根据指定的中断号,删除中断。 |
**表2** 打开、关闭中断
| 接口名 | 描述 |
| -------- | -------- |
| LOS_IntUnLock | 开中断,使能当前处理器所有中断响应。 |
| LOS_IntLock | 关中断,关闭当前处理器所有中断响应。 |
| LOS_IntRestore | 恢复到使用LOS_IntLock、LOS_IntUnLock操作之前的中断状态。 |
## 开发流程
1. 调用中断创建接口LOS_HwiCreate创建中断。
2. 调用中断触发接口LOS_HwiTrigger触发中断。
3. 调用LOS_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。
1. 调用中断创建接口HalHwiCreate创建中断。
2. 调用TestHwiTrigger接口触发指定中断(该接口在测试套中定义,通过写中断控制器的相关寄存器模拟外部中断,一般的外设设备,不需要执行这一步)。
3. 调用HalHwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
......@@ -85,6 +82,7 @@ OpenHarmony LiteOS-M内核的中断模块提供下面几种功能,接口详细
代码实现如下,演示如何创建中断和删除中断,当指定的中断号HWI_NUM_TEST产生中断时,会调用中断处理函数:
```
#include "los_interrupt.h"
......@@ -101,12 +99,10 @@ static UINT32 Example_Interrupt(VOID)
UINT32 ret;
HWI_PRIOR_T hwiPrio = 3;
HWI_MODE_T mode = 0;
HwiIrqParam irqParam;
(void)memset_s(&irqParam, sizeof(HwiIrqParam), 0, sizeof(HwiIrqParam));
irqParam.pDevId = 0;
HWI_ARG_T arg = 0;
/*创建中断*/
ret = LOS_HwiCreate(HWI_NUM_TEST, hwiPrio, mode, (HWI_PROC_FUNC)HwiUsrIrq, &irqParam);
ret = HalHwiCreate(HWI_NUM_TEST, hwiPrio, mode, (HWI_PROC_FUNC)HwiUsrIrq, arg);
if(ret == LOS_OK){
printf("Hwi create success!\n");
} else {
......@@ -114,17 +110,11 @@ static UINT32 Example_Interrupt(VOID)
return LOS_NOK;
}
/*触发中断*/
ret = LOS_HwiTrigger(HWI_NUM_TEST);
if(ret == LOS_OK){
printf("Hwi trigger success!\n");
} else {
printf("Hwi trigger failed!\n");
return LOS_NOK;
}
/* 延时50个Ticks, 当有硬件中断发生时,会调用函数HwiUsrIrq*/
LOS_TaskDelay(50);
/*删除中断*/
ret = LOS_HwiDelete(HWI_NUM_TEST);
ret = HalHwiDelete(HWI_NUM_TEST);
if(ret == LOS_OK){
printf("Hwi delete success!\n");
} else {
......@@ -141,9 +131,8 @@ static UINT32 Example_Interrupt(VOID)
编译运行得到的结果为:
```
Hwi create success!
in the func HwiUsrIrq
Hwi trigger success!
Hwi delete success!
```
# 事件
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [事件控制块](#事件控制块)
- [事件运作原理](#事件运作原理)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -29,6 +19,7 @@
### 事件控制块
```
/**
* 事件控制块数据结构
......@@ -60,20 +51,20 @@ typedef struct tagEvent {
**事件销毁**:销毁指定的事件控制块。
**图1** 轻量系统事件运作原理图
![zh-cn_image_0000001200771972](figures/zh-cn_image_0000001200771972.png)
**图1** 轻量系统事件运作原理图
![zh-cn_image_0000001200771972](figures/zh-cn_image_0000001200771972.png)
## 接口说明
| 功能分类 | 接口名 | 描述 |
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 事件检测 | LOS_EventPoll | 根据eventID,eventMask(事件掩码),mode(事件读取模式),检查用户期待的事件是否发生。<br/>>&nbsp;![icon-notice.gif](public_sys-resources/icon-notice.gif)&nbsp;**须知:**<br/>>&nbsp;当mode含LOS_WAITMODE_CLR,且用户期待的事件发生时,此时eventID中满足要求的事件会被清零,这种情况下eventID既是入参也是出参。其他情况eventID只作为入参。 |
| 初始化 | LOS_EventInit | 事件控制块初始化。 |
| 事件读 | LOS_EventRead | 读事件(等待事件),任务会根据timeOut(单位:tick)进行阻塞等待;<br/>未读取到事件时,返回值为0;<br/>正常读取到事件时,返回正值(事件发生的集合);<br/>其他情况返回特定错误码。 |
| 事件写 | LOS_EventWrite | 写一个特定的事件到事件控制块。 |
| 事件清除 | LOS_EventClear | 根据events掩码,清除事件控制块中的事件。 |
| 事件销毁 | LOS_EventDestroy | 事件控制块销毁。 |
| 事件检测 | LOS_EventPoll | 根据eventID,eventMask(事件掩码),mode(事件读取模式),检查用户期待的事件是否发生。<br/>&nbsp;![icon-notice.gif](public_sys-resources/icon-notice.gif)&nbsp;**须知:**<br/>&nbsp;当mode含LOS_WAITMODE_CLR,且用户期待的事件发生时,此时eventID中满足要求的事件会被清零,这种情况下eventID既是入参也是出参。其他情况eventID只作为入参。 |
| 初始化 | LOS_EventInit | 事件控制块初始化。 |
| 事件读 | LOS_EventRead | 读事件(等待事件),任务会根据timeOut(单位:tick)进行阻塞等待;<br/>未读取到事件时,返回值为0;<br/>正常读取到事件时,返回正值(事件发生的集合);<br/>其他情况返回特定错误码。 |
| 事件写 | LOS_EventWrite | 写一个特定的事件到事件控制块。 |
| 事件清除 | LOS_EventClear | 根据events掩码,清除事件控制块中的事件。 |
| 事件销毁 | LOS_EventDestroy | 事件控制块销毁。 |
## 开发流程
......@@ -121,6 +112,7 @@ typedef struct tagEvent {
示例代码如下:
```
#include "los_event.h"
#include "los_task.h"
......@@ -207,6 +199,7 @@ UINT32 Example_TaskEntry(VOID)
编译运行得到的结果为:
```
Example_Event wait event 0x1
Example_TaskEntry write event.
......
# 互斥锁
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -24,20 +16,18 @@
用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务如果想访问这个公共资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性。
**图1** 轻量系统互斥锁运作示意图
![zh-cn_image_0000001245411845](figures/zh-cn_image_0000001245411845.png)
**图1** 轻量系统互斥锁运作示意图
![zh-cn_image_0000001245411845](figures/zh-cn_image_0000001245411845.png)
## 接口说明
**表1** 互斥锁模块接口
**表1** 互斥锁模块接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 互斥锁的创建和删除 | LOS_MuxCreate | 创建互斥锁 |
| | LOS_MuxDelete | 删除指定的互斥锁 |
| 互斥锁的申请和释放 | LOS_MuxPend | 申请指定的互斥锁 |
| | LOS_MuxPost | 释放指定的互斥锁 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 互斥锁的创建和删除 | LOS_MuxCreate:创建互斥锁<br/>LOS_MuxDelete:删除指定的互斥锁 |
| 互斥锁的申请和释放 | LOS_MuxPend:申请指定的互斥锁<br/>LOS_MuxPost:释放指定的互斥锁 |
## 开发流程
......@@ -89,6 +79,7 @@
示例代码如下:
```
#include <string.h>
#include "los_mux.h"
......@@ -193,7 +184,8 @@ UINT32 Example_TaskEntry(VOID)
### 结果验证
编译运行得到的结果为:
编译运行得到的结果为:
```
task2 try to get mutex, wait forever.
task2 get mutex g_testMux and suspend 100 ticks.
......
# 消息队列
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [队列控制块](#队列控制块)
- [队列运作原理](#队列运作原理)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -41,6 +31,7 @@
### 队列控制块
```
/**
* 队列控制块数据结构
......@@ -81,25 +72,21 @@ typedef struct
- 删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态,并释放队列所占内存。
**图1** 队列读写数据操作示意图
![zh-cn_image_0000001200452026](figures/zh-cn_image_0000001200452026.png)
**图1** 队列读写数据操作示意图
![zh-cn_image_0000001200452026](figures/zh-cn_image_0000001200452026.png)
上图对读写队列做了示意,图中只画了尾节点写入方式,没有画头节点写入,但是两者是类似的。
## 接口说明
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 创建/删除消息队列 | LOS_QueueCreate | 创建一个消息队列,由系统动态申请队列空间。 |
| | LOS_QueueDelete | 根据队列ID删除一个指定队列。 |
| 读/写队列(不带拷贝) | LOS_QueueRead | 读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)。 |
| | LOS_QueueWrite | 向指定队列尾节点中写入入参bufferAddr的值(即buffer的地址)。 |
| | LOS_QueueWriteHead | 向指定队列头节点中写入入参bufferAddr的值(即buffer的地址)。 |
| 读/写队列(带拷贝) | LOS_QueueReadCopy | 读取指定队列头节点中的数据。 |
| | LOS_QueueWriteCopy | 向指定队列尾节点中写入入参bufferAddr中保存的数据。 |
| | LOS_QueueWriteHeadCopy | 向指定队列头节点中写入入参bufferAddr中保存的数据。 |
| 获取队列信息 | LOS_QueueInfoGet | 获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务。 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 创建/删除消息队列 | -&nbsp;LOS_QueueCreate:创建一个消息队列,由系统动态申请队列空间。<br/>-&nbsp;LOS_QueueDelete:根据队列ID删除一个指定队列。 |
| 读/写队列(不带拷贝) | -&nbsp;LOS_QueueRead:读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)。<br/>-&nbsp;LOS_QueueWrite:向指定队列尾节点中写入入参bufferAddr的值(即buffer的地址)。<br/>-&nbsp;LOS_QueueWriteHead:向指定队列头节点中写入入参bufferAddr的值(即buffer的地址)。 |
| 读/写队列(带拷贝) | -&nbsp;LOS_QueueReadCopy:读取指定队列头节点中的数据。<br/>-&nbsp;LOS_QueueWriteCopy:向指定队列尾节点中写入入参bufferAddr中保存的数据。<br/>-&nbsp;LOS_QueueWriteHeadCopy:向指定队列头节点中写入入参bufferAddr中保存的数据。 |
| 获取队列信息 | LOS_QueueInfoGet:获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务。 |
## 开发流程
......@@ -127,7 +114,7 @@ typedef struct
> - 鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,用户必须保证调用LOS_QueueRead获取到的指针所指向的内存区域在读队列期间没有被异常修改或释放,否则可能导致不可预知的后果。
>
> - LOS_QueueReadCopy接口的读取长度如果小于消息实际长度,消息将被截断。
>
>
> - 鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,也就意味着实际写和读的消息长度仅仅是一个指针数据,因此用户使用这组接口之前,需确保创建队列时的消息节点大小,为一个指针的长度,避免不必要的浪费和读取失败。
......@@ -153,6 +140,7 @@ typedef struct
示例代码如下:
```
#include "los_task.h"
#include "los_queue.h"
......@@ -239,6 +227,7 @@ UINT32 ExampleQueue(VOID)
编译运行得到的结果为:
```
start queue example.
create the queue success.
......
# 信号量
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [信号量控制块](#信号量控制块)
- [信号量运作原理](#信号量运作原理)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -33,6 +23,7 @@
### 信号量控制块
```
/**
* 信号量控制块数据结构
......@@ -42,7 +33,8 @@ typedef struct {
UINT16 semType; /* 信号量类型 */
UINT16 semCount; /* 信号量计数 */
UINT16 semId; /* 信号量索引号 */
LOS_DL_LIST semList; /* 用于插入阻塞于信号量的任务 */} LosSemCB;
LOS_DL_LIST semList; /* 用于插入阻塞于信号量的任务 */
} LosSemCB;
```
......@@ -60,19 +52,16 @@ typedef struct {
信号量允许多个任务在同一时刻访问共享资源,但会限制同一时刻访问此资源的最大任务数目。当访问资源的任务数达到该资源允许的最大数量时,会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。
**图1** 轻量系统信号量运作示意图
![zh-cn_image_0000001245051881](figures/zh-cn_image_0000001245051881.png)
**图1** 轻量系统信号量运作示意图
![zh-cn_image_0000001245051881](figures/zh-cn_image_0000001245051881.png)
## 接口说明
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 创建/删除信号量 | LOS_SemCreate | 创建信号量,返回信号量ID |
| | LOS_BinarySemCreate | 创建二值信号量,其计数值最大为1 |
| | LOS_SemDelete | 删除指定的信号量 |
| 申请/释放信号量 | LOS_SemPend | 申请指定的信号量,并设置超时时间 |
| | LOS_SemPost | 释放指定的信号量 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 创建/删除信号量 | -&nbsp;LOS_SemCreate:创建信号量,返回信号量ID<br/>-&nbsp;LOS_BinarySemCreate:创建二值信号量,其计数值最大为1<br/>-&nbsp;LOS_SemDelete:删除指定的信号量 |
| 申请/释放信号量 | -&nbsp;LOS_SemPend:申请指定的信号量,并设置超时时间<br/>-&nbsp;LOS_SemPost:释放指定的信号量 |
## 开发流程
......@@ -97,7 +86,7 @@ typedef struct {
本实例实现如下功能:
1. 测试任务ExampleSem创建一个信号量,锁任务调度,创建两个任务ExampleSemTask1、ExampleSemTask2, ExampleSemTask2优先级高于ExampleSemTask1,两个任务中申请同一信号量,解锁任务调度后两任务阻塞,测试任务ExampleSem释放信号量。
1. 测试任务ExampleSem创建一个信号量,锁任务调度。创建两个任务ExampleSemTask1和ExampleSemTask2, ExampleSemTask2优先级高于ExampleSemTask1。两个任务中申请同一信号量,解锁任务调度后两任务阻塞,测试任务ExampleSem释放信号量。
2. ExampleSemTask2得到信号量,被调度,然后任务休眠20Tick,ExampleSemTask2延迟,ExampleSemTask1被唤醒。
......@@ -112,6 +101,7 @@ typedef struct {
示例代码如下:
```
#include "los_sem.h"
#include "securec.h"
......@@ -231,6 +221,7 @@ UINT32 ExampleSem(VOID)
编译运行得到的结果为:
```
ExampleSemTask2 try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
......
# 内核通信机制
- **[事件](kernel-mini-basic-ipc-event.md)**
- **[互斥锁](kernel-mini-basic-ipc-mutex.md)**
......
# 基本概念
内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。
......
# 动态内存
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [使用场景](#使用场景)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 运行机制
......@@ -14,10 +7,10 @@
OpenHarmony LiteOS-M动态内存在TLSF算法的基础上,对区间的划分进行了优化,获得更优的性能,降低了碎片率。动态内存核心算法框图如下:
**图1** 轻量系统动态内存核心算法
![zh-cn_image_0000001199352445](figures/zh-cn_image_0000001199352445.png)
**图1** 轻量系统动态内存核心算法
![zh-cn_image_0000001199352445](figures/zh-cn_image_0000001199352445.png)
$$根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:[4, 127]和[2^{7}$, 2^{31}$],如上图size class所示:
根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:[4, 127]和[2<sup>7</sup>, 2<sup>31</sup>],如上图size class所示:
1. 对[4,127]区间的内存进行等分,如上图下半部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。[4,127]区间的31个小区间内存对应31个比特位进行标记链表是否为空。
......@@ -27,8 +20,8 @@ $$根据空闲内存块的大小,使用多个空闲链表来管理。根据内
内存管理结构如下图所示:
**图2** 轻量系统动态内存管理结构图
![zh-cn_image_0000001153313284](figures/zh-cn_image_0000001153313284.png)
**图2** 轻量系统动态内存管理结构图
![zh-cn_image_0000001153313284](figures/zh-cn_image_0000001153313284.png)
- 内存池池头部分
内存池池头部分包含内存池信息、位图标记数组和空闲链表数组。内存池信息包含内存池起始地址及堆区域总大小,内存池属性。位图标记数组有7个32位无符号整数组成,每个比特位标记对应的空闲链表是否挂载空闲内存块节点。空闲内存链表包含223个空闲内存头节点信息,每个空闲内存头节点信息维护内存节点头和空闲链表中的前驱、后继空闲内存节点。
......@@ -38,8 +31,8 @@ $$根据空闲内存块的大小,使用多个空闲链表来管理。根据内
一些芯片片内RAM大小无法满足要求,需要使用片外物理内存进行扩充。对于这样的多段非连续性内存, LiteOS-M内核支持把多个非连续性内存逻辑上合一,用户不感知底层的多段非连续性内存区域。 LiteOS-M内核内存模块把不连续的内存区域作为空闲内存结点插入到空闲内存节点链表,把不同内存区域间的不连续部分标记为虚拟的已使用内存节点,从逻辑上把多个非连续性内存区域实现为一个统一的内存池。下面通过示意图说明下多段非连续性内存的运行机制:
**图3** 非连续性内存合一示意图
![zh-cn_image_0000001198253551](figures/zh-cn_image_0000001198253551.png)
**图3** 非连续性内存合一示意图
![zh-cn_image_0000001198253551](figures/zh-cn_image_0000001198253551.png)
结合上述示意图,非连续性内存合并为一个统一的内存池的步骤如下:
......@@ -66,24 +59,16 @@ $$根据空闲内存块的大小,使用多个空闲链表来管理。根据内
OpenHarmony LiteOS-M的动态内存管理主要为用户提供以下功能,接口详细信息可以查看API参考。
**表1** 动态内存模块接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 初始化和删除内存池 | LOS_MemInit | 初始化一块指定的动态内存池,大小为size。 |
| | LOS_MemDeInit | 删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效。 |
| 申请、释放动态内存 | LOS_MemAlloc | 从指定动态内存池中申请size长度的内存。 |
| | LOS_MemFree | 释放从指定动态内存中申请的内存。 |
| | LOS_MemRealloc | 按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块。 |
| | LOS_MemAllocAlign | 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存。 |
| 获取内存池信息 | LOS_MemPoolSizeGet | 获取指定动态内存池的总大小。 |
| | LOS_MemTotalUsedGet | 获取指定动态内存池的总使用量大小。 |
| | LOS_MemInfoGet | 获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小。 |
| | LOS_MemPoolList | 打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效。 |
| 获取内存块信息 | LOS_MemFreeNodeShow | 打印指定内存池的空闲内存块的大小及数量。 |
| | LOS_MemUsedNodeShow | 打印指定内存池的已使用内存块的大小及数量。 |
| 检查指定内存池的完整性 | LOS_MemIntegrityCheck | 对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效。 |
| 增加非连续性内存区域 | LOS_MemRegionsAdd | 支持多段非连续性内存区域,把非连续性内存区域逻辑上整合为一个统一的内存池。仅打开LOSCFG_MEM_MUL_REGIONS时有效。如果内存池指针参数pool为空,则使用多段内存的第一个初始化为内存池,其他内存区域,作为空闲节点插入;如果内存池指针参数pool不为空,则把多段内存作为空闲节点,插入到指定的内存池。 |
**表1** 动态内存模块接口
| 功能分类 | 接口描述 |
| -------- | -------- |
| 初始化和删除内存池 | -&nbsp;LOS_MemInit:初始化一块指定的动态内存池,大小为size。<br/>-&nbsp;LOS_MemDeInit:删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效。 |
| 申请、释放动态内存 | -&nbsp;LOS_MemAlloc:从指定动态内存池中申请size长度的内存。<br/>-&nbsp;LOS_MemFree:释放从指定动态内存中申请的内存。<br/>-&nbsp;LOS_MemRealloc:释放从指定动态内存中申请的内存。 |
| 获取内存池信息 | -&nbsp;LOS_MemPoolSizeGet:获取指定动态内存池的总大小。<br/>-&nbsp;LOS_MemTotalUsedGet:获取指定动态内存池的总使用量大小。<br/>-&nbsp;LOS_MemInfoGet:获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小。<br/>-&nbsp;LOS_MemPoolList:打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效。 |
| 获取内存块信息 | -&nbsp;LOS_MemFreeNodeShow:打印指定内存池的空闲内存块的大小及数量。<br/>-&nbsp;LOS_MemUsedNodeShow:打印指定内存池的已使用内存块的大小及数量。 |
| 检查指定内存池的完整性 | LOS_MemIntegrityCheck:对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效。 |
| 增加非连续性内存区域 | LOS_MemRegionsAdd:支持多段非连续性内存区域,把非连续性内存区域逻辑上整合为一个统一的内存池。仅打开LOSCFG_MEM_MUL_REGIONS时有效。如果内存池指针参数pool为空,则使用多段内存的第一个初始化为内存池,其他内存区域,作为空闲节点插入;如果内存池指针参数pool不为空,则把多段内存作为空闲节点,插入到指定的内存池。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 由于动态内存管理需要管理控制块数据结构来管理内存,这些数据结构会额外消耗内存,故实际用户可使用内存总量小于配置项OS_SYS_MEM_SIZE的大小。
......@@ -123,6 +108,7 @@ OpenHarmony LiteOS-M的动态内存管理主要为用户提供以下功能,接
示例代码如下:
```
#include "los_memory.h"
#define TEST_POOL_SIZE (2*1024)
......@@ -170,6 +156,7 @@ VOID Example_DynMem(VOID)
输出结果如下:
```
Mem init success!
Mem alloc success!
......
# 静态内存
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [使用场景](#使用场景)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 运行机制
......@@ -14,8 +7,8 @@
静态内存池由一个控制块LOS_MEMBOX_INFO和若干相同大小的内存块LOS_MEMBOX_NODE构成。控制块位于内存池头部,用于内存块管理,包含内存块大小uwBlkSize,内存块数量uwBlkNum,已分配使用的内存块数量uwBlkCnt和空闲内存块链表stFreeList。内存块的申请和释放以块大小为粒度,每个内存块包含指向下一个内存块的指针pstNext。
**图1** 静态内存示意图
![zh-cn_image_0000001199352039](figures/zh-cn_image_0000001199352039.png)
**图1** 静态内存示意图
![zh-cn_image_0000001199352039](figures/zh-cn_image_0000001199352039.png)
## 开发指导
......@@ -30,16 +23,14 @@
OpenHarmony LiteOS-M的静态内存管理主要为用户提供以下功能,接口详细信息可以查看API参考。
**表1** 静态内存模块接口
**表1** 静态内存模块接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 初始化静态内存池 | LOS_MemboxInit | 初始化一个静态内存池,根据入参设定其起始地址、总大小及每个内存块大小。 |
| 清除静态内存块内容 | LOS_MemboxClr | 清零从静态内存池中申请的静态内存块的内容。 |
| 申请、释放静态内存 | LOS_MemboxAlloc | 从指定的静态内存池中申请一块静态内存块。 |
| | LOS_MemboxFree | 释放从静态内存池中申请的一块静态内存块。 |
| 获取、打印静态内存池信息 | LOS_MemboxStatisticsGet | 获取指定静态内存池的信息,包括内存池中总内存块数量、已经分配出去的内存块数量、每个内存块的大小。 |
| | LOS_ShowBox | 打印指定静态内存池所有节点信息(打印等级是LOS_INFO_LEVEL),包括内存池起始地址、内存块大小、总内存块数量、每个空闲内存块的起始地址、所有内存块的起始地址。 |
| 功能分类 | 接口名 |
| -------- | -------- |
| 初始化静态内存池 | LOS_MemboxInit:初始化一个静态内存池,根据入参设定其起始地址、总大小及每个内存块大小。 |
| 清除静态内存块内容 | LOS_MemboxClr:清零从静态内存池中申请的静态内存块的内容。 |
| 申请、释放静态内存 | -&nbsp;LOS_MemboxAlloc:从指定的静态内存池中申请一块静态内存块。<br/>-&nbsp;LOS_MemboxFree:释放从静态内存池中申请的一块静态内存块。 |
| 获取、打印静态内存池信息 | -&nbsp;LOS_MemboxStatisticsGet:获取指定静态内存池的信息,包括内存池中总内存块数量、已经分配出去的内存块数量、每个内存块的大小。<br/>-&nbsp;LOS_ShowBox:打印指定静态内存池所有节点信息(打印等级是LOS_INFO_LEVEL),包括内存池起始地址、内存块大小、总内存块数量、每个空闲内存块的起始地址、所有内存块的起始地址。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 初始化后的内存池的内存块数量,不等于总大小除于内存块大小,因为内存池的控制块和每个内存块的控制头,都存在内存开销,设置总大小时,需要将这些因素考虑进去。
......@@ -81,6 +72,7 @@ OpenHarmony LiteOS-M的静态内存管理主要为用户提供以下功能,接
6. 释放该内存块。
示例代码如下:
```
#include "los_membox.h"
......@@ -134,6 +126,7 @@ VOID Example_StaticMem(VOID)
输出结果如下:
```
Membox init success!
Mem alloc success!
......
# 内存管理
- **[基本概念](kernel-mini-basic-memory-basic.md)**
- **[静态内存](kernel-mini-basic-memory-static.md)**
......
# 软件定时器
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [定时器状态](#定时器状态)
- [定时器模式](#定时器模式)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -72,15 +62,13 @@ OpenHarmony LiteOS-M内核的软件定时器提供三类定时器机制:
OpenHarmony LiteOS-M内核的软件定时器模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** 软件定时器接口
**表1** 软件定时器接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 创建、删除定时器 | LOS_SwtmrCreate | 创建定时器 |
| | LOS_SwtmrDelete | 删除定时器 |
| 启动、停止定时器 | LOS_SwtmrStart | 启动定时器 |
| | LOS_SwtmrStop | 停止定时器 |
| 获得软件定时器剩余Tick数 | LOS_SwtmrTimeGet | 获得软件定时器剩余Tick数 |
| 功能分类 | p接口描述 |
| -------- | -------- |
| 创建、删除定时器 | -&nbsp;LOS_SwtmrCreate:创建定时器<br/>-&nbsp;LOS_SwtmrDelete:删除定时器 |
| 启动、停止定时器 | -&nbsp;LOS_SwtmrStart:启动定时器<br/>-&nbsp;LOS_SwtmrStop:停止定时器 |
| 获得软件定时器剩余Tick数 | LOS_SwtmrTimeGet:获得软件定时器剩余Tick数 |
## 开发流程
......@@ -142,6 +130,7 @@ OpenHarmony LiteOS-M内核的软件定时器模块提供下面几种功能,接
代码实现如下:
```
#include "los_swtmr.h"
......@@ -238,6 +227,7 @@ UINT32 Example_TaskEntry(VOID)
编译烧录运行,输出结果如下:
```
create Timer1 success
start Timer1 success
......
# 任务管理
- [基本概念](#基本概念)
- [任务相关概念](#任务相关概念)
- [任务运行机制](#任务运行机制)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 基本概念
......@@ -43,8 +36,9 @@ OpenHarmony LiteOS-M的任务模块可以给用户提供多个任务,实现任
**任务状态迁移**
**图1** 任务状态示意图
![zh-cn_image_0000001200612002](figures/zh-cn_image_0000001200612002.png)
**图1** 任务状态示意图
![zh-cn_image_0000001200612002](figures/zh-cn_image_0000001200612002.png)
**任务状态迁移说明:**
......@@ -107,36 +101,16 @@ OpenHarmony LiteOS-M的任务模块可以给用户提供多个任务,实现任
OpenHarmony LiteOS-M内核的任务管理模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** 任务管理模块接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 创建和删除任务 | LOS_TaskCreateOnly | 创建任务,并使该任务进入suspend状态,不对该任务进行调度。如果需要调度,可以调用LOS_TaskResume使该任务进入ready状态。 |
| | LOS_TaskCreate | 创建任务,并使该任务进入ready状态,如果就绪队列中没有更高优先级的任务,则运行该任务。 |
| | LOS_TaskDelete | 删除指定的任务。 |
| 控制任务状态 | LOS_TaskResume | 恢复挂起的任务,使该任务进入ready状态。 |
| | LOS_TaskSuspend | 挂起指定的任务,然后切换任务。 |
| | LOS_TaskJoin | 挂起当前任务,等待指定任务运行结束并回收其任务控制块资源。 |
| | LOS_TaskDetach | 修改任务的joinable属性为detach属性,detach属性的任务运行结束会自动回收任务控制块资源。 |
| | LOS_TaskDelay | 任务延时等待,释放CPU,等待时间到期后该任务会重新进入ready状态。传入参数为Tick数目。 |
| | LOS_Msleep | 传入参数为毫秒数,转换为Tick数目,调用LOS_TaskDelay。 |
| | LOS_TaskYield | 当前任务时间片设置为0,释放CPU,触发调度运行就绪任务队列中优先级最高的任务。 |
| 控制任务调度 | LOS_TaskLock | 锁任务调度,但任务仍可被中断打断。 |
| | LOS_TaskUnlock | 解锁任务调度。 |
| | LOS_Schedule | 触发任务调度。 |
| 控制任务优先级 | LOS_CurTaskPriSet | 设置当前任务的优先级。 |
| | LOS_TaskPriSet | 设置指定任务的优先级。 |
| | LOS_TaskPriGet | 获取指定任务的优先级。 |
| 获取任务信息 | LOS_CurTaskIDGet | 获取当前任务的ID。 |
| | LOS_NextTaskIDGet | 获取任务就绪队列中优先级最高的任务的ID。 |
| | LOS_NewTaskIDGet | 等同LOS_NextTaskIDGet。 |
| | LOS_CurTaskNameGet | 获取当前任务的名称。 |
| | LOS_TaskNameGet | 获取指定任务的名称。 |
| | LOS_TaskStatusGet | 获取指定任务的状态。 |
| | LOS_TaskInfoGet | 获取指定任务的信息,包括任务状态、优先级、任务栈大小、栈顶指针SP、任务入口函数、已使用的任务栈大小等。 |
| | LOS_TaskIsRunning | 获取任务模块是否已经开始调度运行。 |
| 任务信息维测 | LOS_TaskSwitchInfoGet | 获取任务切换信息,需要开启宏LOSCFG_BASE_CORE_EXC_TSK_SWITCH。 |
| 回收任务栈资源 | LOS_TaskResRecycle | 回收所有待回收的任务栈资源。 |
**表1** 任务管理模块接口
| 功能分类 | 接口描述 |
| -------- | -------- |
| 创建和删除任务 | LOS_TaskCreateOnly:创建任务,并使该任务进入ready状态,如果就绪队列中没有更高优先级的任务,则运行该任务。<br/>LOS_TaskCreate:创建任务,并使该任务进入ready状态,如果就绪队列中没有更高优先级的任务,则运行该任务。<br/>LOS_TaskDelete:删除指定的任务。 |
| 控制任务状态 | LOS_TaskResume:恢复挂起的任务,使该任务进入ready状态。<br/>LOS_TaskSuspend:挂起指定的任务,然后切换任务。<br/>LOS_TaskJoin:挂起当前任务,等待指定任务运行结束并回收其任务控制块资源<br/>LOS_TaskDelay:任务延时等待,释放CPU,等待时间到期后该任务会重新进入ready状态。传入参数为Tick数目。<br/>LOS_Msleep:传入参数为毫秒数,转换为Tick数目,调用LOS_TaskDelay。<br/>LOS_TaskYield:当前任务时间片设置为0,释放CPU,触发调度运行就绪任务队列中优先级最高的任务。 |
| 控制任务调度 | LOS_TaskLock:锁任务调度,但任务仍可被中断打断。<br/>LOS_TaskUnlock:解锁任务调度。<br/>LOS_Schedule:触发任务调度。 |
| 控制任务优先级 | LOS_CurTaskPriSet:设置当前任务的优先级。<br/>LOS_TaskPriSet:设置指定任务的优先级。<br/>LOS_TaskPriGet:获取指定任务的优先级。 |
| 获取任务信息 | LOS_CurTaskIDGet:获取当前任务的ID。<br/>LOS_NextTaskIDGet:获取任务就绪队列中优先级最高的任务的ID。<br/>LOS_NewTaskIDGet:等同LOS_NextTaskIDGet。<br/>LOS_CurTaskNameGet:获取当前任务的名称。<br/>LOS_TaskNameGet:获取指定任务的名称。<br/>LOS_TaskStatusGet:获取指定任务的状态。<br/>LOS_TaskInfoGet:获取指定任务的信息,包括任务状态、优先级、任务栈大小、栈顶指针SP、任务入口函数、已使用的任务栈大小等。<br/>LOS_TaskIsRunning:获取任务模块是否已经开始调度运行。 |
| 任务信息维测 | LOS_TaskSwitchInfoGet:获取任务切换信息,需要开启宏LOSCFG_BASE_CORE_EXC_TSK_SWITCH。 |
## 开发流程
......@@ -187,6 +161,7 @@ OpenHarmony LiteOS-M内核的任务管理模块提供下面几种功能,接口
本实例介绍基本的任务操作方法,包含2个不同优先级任务的创建、任务延时、任务锁与解锁调度、挂起和恢复等操作,阐述任务优先级调度的机制以及各接口的应用。示例代码如下:
```
UINT32 g_taskHiId;
UINT32 g_taskLoId;
......@@ -304,6 +279,7 @@ UINT32 Example_TskCaseEntry(VOID)
编译运行得到的结果为:
```
LOS_TaskLock() Success!
Example_TaskHi create Success!
......
# 基础内核
- **[中断管理](kernel-mini-basic-interrupt.md)**
- **[任务管理](kernel-mini-basic-task.md)**
......
# 内核调测
- **[内存调测](kernel-mini-memory-debug.md)**
- **[异常调测](kernel-mini-memory-exception.md)**
......
# CPU占用率
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -43,16 +35,13 @@ OpenHarmony LiteOS-M提供以下两种CPU占用率的信息查询:
## 接口说明
**表1** 功能列表
**表1** 功能列表
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 获取系统CPU占用率 | LOS_SysCpuUsage | 获取当前系统CPU占用率 |
| | LOS_HistorySysCpuUsage | 获取系统历史CPU占用率 |
| 获取任务CPU占用率 | LOS_TaskCpuUsage | 获取指定任务CPU占用率 |
| | LOS_HistoryTaskCpuUsage | 获取指定任务历史CPU占用率 |
| | LOS_AllCpuUsage | 获取所有任务CPU占用率 |
| 输出任务CPU占用率 | LOS_CpupUsageMonitor | 输出任务历史CPU占用率 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 获取系统CPU占用率 | -&nbsp;LOS_SysCpuUsage:获取当前系统CPU占用率<br/>-&nbsp;LOS_HistorySysCpuUsage:获取系统历史CPU占用率 |
| 获取任务CPU占用率 | -&nbsp;LOS_TaskCpuUsage:获取指定任务CPU占用率<br/>-&nbsp;LOS_HistoryTaskCpuUsage:获取指定任务历史CPU占用率<br/>-&nbsp;LOS_HistoryTaskCpuUsage:获取指定任务历史CPU占用率 |
| 输出任务CPU占用率 | LOS_CpupUsageMonitor:输出任务历史CPU占用率 |
## 开发流程
......@@ -102,6 +91,7 @@ CPU占用率的典型开发流程:
代码实现如下:
```
#include "los_task.h"
#include "los_cpup.h"
......@@ -155,7 +145,8 @@ UINT32 ItCpupTest(VOID)
### 结果验证
编译运行得到的结果为:
编译运行得到的结果为:
```
entry cpup test example
the current system cpu usage is : 1.5
......
# 动态加载
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [符号表导出](#符号表导出)
- [ELF文件加载](#elf文件加载)
- [ELF文件链接](#elf文件链接)
- [ELF支持规格](#elf支持规格)
- [ELF支持类型](#elf支持类型)
- [ELF共享库编译链接选项](#elf共享库编译链接选项)
## 基本概念
在硬件资源有限的小设备中,需要通过算法的动态部署能力来解决无法同时部署多种算法的问题。以开发者易用为主要考虑因素,同时考虑到多平台的通用性,LiteOS-M选择业界标准的ELF加载方案,方便拓展算法生态。LiteOS-M提供类似于dlopen、dlsym等接口,APP通过动态加载模块提供的接口可以加载、卸载相应算法库。如图1所示,APP需要通过三方算法库所需接口获取对应信息输出,三方算法库又依赖内核提供的基本接口,如malloc等。APP加载所需接口,并对相关的未定义符号完成重定位后,APP即可调用该接口完成功能调用。目前动态加载组件只支持arm架构。此外,待加载的共享库需要验签或者限制来源,确保系统的安全性。
**图1** LiteOS-M内核动态加载架构图
![zh-cn_image_0000001200292052](figures/zh-cn_image_0000001200292052.png)
**图1** LiteOS-M内核动态加载架构图
![zh-cn_image_0000001200292052](figures/zh-cn_image_0000001200292052.png)
## 运行机制
......@@ -24,6 +16,7 @@
共享库调用内核接口需要内核主动暴露动态库所需的接口,如图2所示,该机制将符号信息编译到指定段中,调用SYM_EXPORT宏即可完成对指定符号的信息导出。符号信息通过结构体SymInfo描述,成员包括符号名和符号地址信息,宏SYM_EXPORT通过__attribute__编译属性将符号信息导入.sym.\*段中。
```
typedef struct {
CHAR *name;
......@@ -37,14 +30,16 @@ const SymInfo sym_##func __attribute__((section(".sym."#func))) = { \
};
```
**图2** 导出的符号表信息
![zh-cn_image_0000001245171875](figures/zh-cn_image_0000001245171875.png)
**图2** 导出的符号表信息
![zh-cn_image_0000001245171875](figures/zh-cn_image_0000001245171875.png)
### ELF文件加载
加载过程中,根据ELF文件的句柄以及程序头表的段偏移可以得到需要加载到内存的LOAD段,一般有两个段,只读段及读写段,如下所示,可以用readelf -l查看ELF文件的LOAD段信息。如图3所示,根据相应的对齐属性申请物理内存,通过每个段的加载基址及偏移将代码段或数据段写入内存中。
```
$ readelf -l lib.so
......@@ -66,16 +61,17 @@ Program Headers:
03 .dynamic
```
**图3** ELF文件的加载过程
![zh-cn_image_0000001245251887](figures/zh-cn_image_0000001245251887.png)
**图3** ELF文件的加载过程
![zh-cn_image_0000001245251887](figures/zh-cn_image_0000001245251887.png)
### ELF文件链接
如图4所示,通过ELF文件的.dynamic段获取重定位表,遍历表中每一个需要重定位的条目,再根据需要重定位的符号名在共享库和内核提供的导出符号表中查找相应符号并更新相应的重定位信息。
**图4** ELF文件的链接过程
![zh-cn_image_0000001200612006](figures/zh-cn_image_0000001200612006.png)
**图4** ELF文件的链接过程
![zh-cn_image_0000001200612006](figures/zh-cn_image_0000001200612006.png)
## ELF支持规格
......
# FAT
- [基本概念](#基本概念)
- [开发指导](#开发指导)
- [驱动适配](#驱动适配)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -27,6 +19,7 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
2、新增fs_config.h文件,配置FS_MAX_SS(存储设备最大sector大小)、FF_VOLUME_STRS(分区名)等信息,例如:
```
#define FF_VOLUME_STRS "system", "inner", "update", "user"
#define FS_MAX_SS 512
......@@ -90,7 +83,8 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
- 系统已将MMC设备分区挂载到user目录
代码实现如下:
代码实现如下:
```
#include <stdio.h>
#include <string.h>
......@@ -185,6 +179,7 @@ int FatfsTest(void)
编译运行得到的结果为:
```
Hello OpenHarmony!
```
# LittleFS
- [基本概念](#基本概念)
- [开发指导](#开发指导)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -16,6 +12,7 @@ LittleFS是一个小型的Flash文件系统,它结合日志结构(log-struct
移植LittleFS到新硬件设备上,需要申明lfs_config:
```
const struct lfs_config cfg = {
// block device operations
......@@ -48,7 +45,8 @@ block_count 可以被擦除的块数量,这取决于块设备的容量及擦
## 示例代码
代码实现如下:
代码实现如下:
```
#include "lfs.h"
#include "stdio.h"
......@@ -100,6 +98,7 @@ int main(void) {
首次编译运行得到的结果为:
```
Say hello 1 times.
```
# 文件系统
M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同A核一样,通过VFS层提供了POSIX标准的操作,保持了接口的一致性,但是因为M核的资源非常紧张,VFS层非常轻薄,没有提供类似A核的高级功能(如pagecache等),主要是接口的标准化和适配工作,具体的事务由各个文件系统实际承载。M核文件系统支持的功能如下表所示:
**表1** 功能列表
| 功能分类 | 接口名 | 描述 | FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- | -------- |
| 文件操作 | open | 打开文件 | 支持 | 支持 |
| | close | 关闭文件 | 支持 | 支持 |
| | read | 读取文件内容 | 支持 | 支持 |
| | write | 往文件写入内容 | 支持 | 支持 |
| | lseek | 设置文件偏移位置 | 支持 | 支持 |
| | unlink | 删除文件 | 支持 | 支持 |
| | rename | 重命名文件 | 支持 | 支持 |
| | fstat | 通过文件句柄获取文件信息 | 支持 | 支持 |
| | stat | 通过文件路径名获取文件信息 | 支持 | 支持 |
| | fsync | 文件内容刷入存储设备 | 支持 | 支持 |
| 目录操作 | mkdir | 创建目录 | 支持 | 支持 |
| | opendir | 打开目录 | 支持 | 支持 |
| | readdir | 读取目录项内容 | 支持 | 支持 |
| | closedir | 关闭目录 | 支持 | 支持 |
| | rmdir | 删除目录 | 支持 | 支持 |
| 分区操作 | mount | 分区挂载 | 支持 | 支持 |
| | umount | 分区卸载 | 支持 | 支持 |
| | umount2 | 分区卸载,可通过MNT_FORCE参数进行强制卸载 | 支持 | 不支持 |
| | statfs | 获取分区信息 | 支持 | 不支持 |
**表1** 文件操作
| 接口名 | 描述 | FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- |
| open | 打开文件 | 支持 | 支持 |
| close | 关闭文件 | 支持 | 支持 |
| read | 读取文件内容 | 支持 | 支持 |
| write | 往文件写入内容 | 支持 | 支持 |
| lseek | 设置文件偏移位置 | 支持 | 支持 |
| unlink | 删除文件 | 支持 | 支持 |
| rename | 重命名文件 | 支持 | 支持 |
| fstat | 通过文件句柄获取文件信息 | 支持 | 支持 |
| stat | 通过文件路径名获取文件信息 | 支持 | 支持 |
| fsync | 文件内容刷入存储设备 | 支持 | 支持 |
**表2** 目录操作
| 接口名 | 描述 | FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- |
| mkdir | 创建目录 | 支持 | 支持 |
| opendir | 打开目录 | 支持 | 支持 |
| readdir | 读取目录项内容 | 支持 | 支持 |
| closedir | 关闭目录 | 支持 | 支持 |
| rmdir | 删除目录 | 支持 | 支持 |
**表3** 分区操作
| 接口名 | 描述 | FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- |
| mount | 分区挂载 | 支持 | 支持 |
| umount | 分区卸载 | 支持 | 支持 |
| umount2 | 分区卸载,可通过MNT_FORCE参数进行强制卸载 | 支持 | 不支持 |
| statfs | 获取分区信息 | 支持 | 不支持 |
- **[FAT](kernel-mini-extend-file-fat.md)**
......
# C++支持
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -22,7 +16,7 @@ C++代码的识别主要由编译器支持,系统主要对全局对象进行
### 接口说明
**表1** C++支持接口
**表1** C++支持接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
......@@ -33,7 +27,7 @@ C++代码的识别主要由编译器支持,系统主要对全局对象进行
使用C++特性之前,需要调用函数LOS_CppSystemInit,实现C++构造函数初始化,其中被初始化的构造函数存在init_array这个段中,段区间通过变量__init_array_start__、__init_array_end__传递。
**表2** 参数说明
**表2** 参数说明
| 参数 | 参数说明 |
| -------- | -------- |
......@@ -46,6 +40,7 @@ C++代码的识别主要由编译器支持,系统主要对全局对象进行
### 编程实例
```
void app_init(void)
{
......
# 扩展组件
- **[C++支持](kernel-mini-extend-support.md)**
- **[CPU占用率](kernel-mini-extend-cpup.md)**
......
# 内存泄漏检测
- [基础概念](#基础概念)
- [功能配置](#功能配置)
- [开发指导](#开发指导)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基础概念
......@@ -36,6 +29,7 @@
调用LOS_MemUsedNodeShow接口输出的节点信息格式如下:每1行为一个节点信息;第1列为节点地址,可以根据这个地址,使用GDB等手段查看节点完整信息;第2列为节点的大小,等于节点头大小+数据域大小;第3~5列为函数调用关系LR地址,可以根据这个值,结合汇编文件,查看该节点具体申请的位置。
```
node size LR[0] LR[1] LR[2]
0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002
......@@ -69,6 +63,7 @@ node size LR[0] LR[1] LR[2]
代码实现如下:
```
#include <stdio.h>
#include <string.h>
......@@ -89,6 +84,7 @@ void MemLeakTest(void)
编译运行输出log如下:
```
node size LR[0] LR[1] LR[2]
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc
......@@ -109,6 +105,7 @@ node size LR[0] LR[1] LR[2]
对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块:
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
......@@ -116,6 +113,7 @@ node size LR[0] LR[1] LR[2]
部分汇编文件如下:
```
MemLeakTest:
0x80041d4: 0xb510 PUSH {R4, LR}
......
# 踩内存检测
- [基础概念](#基础概念)
- [功能配置](#功能配置)
- [开发指导](#开发指导)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基础概念
......@@ -50,6 +43,7 @@ LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这
代码实现如下:
```
#include <stdio.h>
#include <string.h>
......@@ -72,6 +66,7 @@ void MemIntegrityTest(void)
编译运行输出log如下:
```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
......
# 内存信息统计
- [基础概念](#基础概念)
- [功能配置](#功能配置)
- [开发指导](#开发指导)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基础概念
......@@ -31,6 +24,7 @@ LOSCFG_MEM_WATERLINE:开关宏,默认打开;若关闭这个功能,在tar
关键结构体介绍:
```
typedef struct {
UINT32 totalUsedSize; // 内存池的内存使用量
......@@ -62,7 +56,8 @@ typedef struct {
### 示例代码
代码实现如下:
代码实现如下:
```
#include <stdio.h>
#include <string.h>
......@@ -109,6 +104,7 @@ int MemTest(void)
编译运行输出的结果如下:
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
```
# 内存调测
内存调测方法旨在辅助定位动态内存相关问题,提供了基础的动态内存池信息统计手段,向用户呈现内存池水线、碎片率等信息;提供了内存泄漏检测手段,方便用户准确定位存在内存泄漏的代码行,也可以辅助分析系统各个模块内存的使用情况;提供了踩内存检测手段,可以辅助定位越界踩内存的场景。
......
# 异常调测
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [接口说明](#接口说明)
- [使用指导](#使用指导)
- [开发流程](#开发流程)
- [定位流程](#定位流程)
## 基本概念
......@@ -20,8 +14,8 @@ OpenHarmony LiteOS-M提供异常接管调测手段,帮助开发者定位分析
堆栈分析原理如下图所示,实际堆栈信息根据不同CPU架构有所差异,此处仅做示意。
**图1** 堆栈分析原理示意图
![zh-cn_image_0000001132936268](figures/zh-cn_image_0000001132936268.png)
**图1** 堆栈分析原理示意图
![zh-cn_image_0000001132936268](figures/zh-cn_image_0000001132936268.png)
图中不同颜色的寄存器表示不同的函数。可以看到函数调用过程中,寄存器的保存。通过FP寄存器,栈回溯到异常函数的父函数,继续按照规律对栈进行解析,推出函数调用关系,方便用户定位问题。
......@@ -30,12 +24,11 @@ OpenHarmony LiteOS-M提供异常接管调测手段,帮助开发者定位分析
OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** 回溯栈模块接口
**表1** 回溯栈模块接口
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 回溯栈接口 | LOS_BackTrace | 打印调用处的函数调用栈关系。 |
| | LOS_RecordLR | 在无法打印的场景,用该接口获取调用处的函数调用栈关系。 |
| 功能分类 | 接口名 |
| -------- | -------- |
| 回溯栈接口 | LOS_BackTrace:打印调用处的函数调用栈关系。<br/>LOS_RecordLR:在无法打印的场景,用该接口获取调用处的函数调用栈关系。 |
## 使用指导
......@@ -46,14 +39,15 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
开启异常调测的典型流程如下:
1. 配置异常接管相关宏。
需要在target_config.h头文件中修改配置:
| 配置项 | 含义 | 设置值 |
需要在target_config.h头文件中修改配置:
| 配置项 | 含义 | 设置值 |
| -------- | -------- | -------- |
| LOSCFG_BACKTRACE_DEPTH | 函数调用栈深度,默认15层 | 15 |
| LOSCFG_BACKTRACE_TYPE | 回溯栈类型:<br/>0:表示关闭该功能;<br/>1:表示支持Cortex-m系列硬件的函数调用栈解析;<br/>2:表示用于Risc-v系列硬件的函数调用栈解析; | 根据工具链类型设置1或2 |
1. 使用示例中有问题的代码,编译、运行工程,在串口终端中查看异常信息输出。示例代码模拟异常代码,实际产品开发时使用异常调测机制定位异常问题。
本示例演示异常输出,包含1个任务,该任务入口函数模拟若干函数调用,最终调用一个模拟异常的函数。代码实现如下:
本示例演示异常输出,包含1个任务,该任务入口函数模拟若干函数调用,最终调用一个模拟异常的函数。代码实现如下:
```
#include <stdio.h>
#include "los_config.h"
......@@ -128,6 +122,7 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
```
1. 上述代码串口终端输出异常信息如下:
```
entering kernel init...
LOS_TaskLock() Success!
......@@ -220,6 +215,7 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
异常接管一般的定位步骤如下:
1. 打开编译后生成的镜像反汇编(asm)文件。如果默认没有生成,可以使用objdump工具生成,命令为:
```
arm-none-eabi-objdump -S -l XXX.elf
```
......@@ -227,6 +223,7 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
1. 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。
PC地址指向发生异常时程序正在执行的指令。在当前执行的二进制文件对应的asm文件中,查找PC值0x80037da,找到当前CPU正在执行的指令行,反汇编如下所示:
```
UINT32 Get_Result_Exception_0(UINT16 dividend){
80037c8: b480 push {r7}
......@@ -253,6 +250,7 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
2. 根据LR值查找异常函数的父函数。
包含LR值0x80037fe的反汇编如下所示:
```
080037ec <Get_Result_Exception_1>:
Get_Result_Exception_1():
......
# LMS调测
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [接口说明](#接口说明)
- [开发指导](#开发指导)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -41,7 +33,7 @@ LMS使用影子内存映射标记系统内存的状态,一共可标记为三
OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_m/blob/master/components/lms/los_lms.h)参考。
**表1** LMS模块接口说明
**表1** LMS模块接口说明
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
......@@ -61,7 +53,7 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
1. 配置LMS模块相关宏。
配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_m目录下执行 make update_config命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES:
| 宏 | menuconfig选项 | 含义 | 取值 |
| 宏 | menuconfig选项 | 含义 | 取值 |
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_LMS | Enable&nbsp;Lms&nbsp;Feature | Lms模块的裁剪开关 | YES/NO |
| LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms&nbsp;check&nbsp;pool&nbsp;max&nbsp;num | LMS支持的检测内存池最大个数 | INT |
......@@ -72,7 +64,8 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
2. 在被检测模块的编译脚本中,修改编译选项。
增加LMS检测编译选项-fsanitize=kernel-address。为避免编译器优化,增加-O0编译选项。
gcc与clang编译选项存在差异,参照如下示例:
gcc与clang编译选项存在差异,参照如下示例:
```
if ("$ohos_build_compiler_specified" == "gcc") {
cflags_c = [
......@@ -109,7 +102,8 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
### 示例代码
实例代码如下:
实例代码如下:
```
#define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20
......@@ -168,7 +162,8 @@ UINT32 Example_Lms_test(VOID){
### 结果验证
输出结果如下:
输出结果如下:
```
######LmsTestOsmallocOverflow start ######
[ERR]* Kernel Address Sanitizer Error Detected Start *
......
# Perf调测
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [接口说明](#接口说明)
- [内核态](#内核态)
- [用户态](#用户态)
- [开发指导](#开发指导)
- [内核态开发流程](#内核态开发流程)
- [内核态编程实例](#内核态编程实例)
- [内核态示例代码](#内核态示例代码)
- [内核态结果验证](#内核态结果验证)
- [用户态开发流程](#用户态开发流程)
- [用户态编程实例](#用户态编程实例)
- [用户态示例代码](#用户态示例代码)
- [用户态结果验证](#用户态结果验证)
## 基本概念
......@@ -36,16 +22,14 @@ Perf提供2种工作模式,计数模式和采样模式。
OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h)参考。
**表1** Perf模块接口说明
**表1** Perf模块接口说明
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 开启/停止Perf采样 | LOS_PerfStart | 开启采样 |
| | LOS_PerfStop | 停止采样 |
| 配置Perf采样事件 | LOS_PerfConfig | 配置采样事件的类型、周期等 |
| 读取采样数据 | LOS_PerfDataRead | 读取采样数据到指定地址 |
| 注册采样数据缓冲区的钩子函数 | LOS_PerfNotifyHookReg | 注册缓冲区水线到达的处理钩子 |
| | LOS_PerfFlushHookReg | 注册缓冲区刷cache的钩子 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 开启/停止Perf采样 | LOS_PerfStart:开启采样<br/>LOS_PerfStop:停止采样 |
| 配置Perf采样事件 | LOS_PerfConfig:配置采样事件的类型、周期等 |
| 读取采样数据 | LOS_PerfDataRead:读取采样数据到指定地址 |
| 注册采样数据缓冲区的钩子函数 | LOS_PerfNotifyHookReg:注册缓冲区水线到达的处理钩子<br/>LOS_PerfFlushHookReg:注册缓冲区刷cache的钩子 |
1. Perf采样事件的结构体为PerfConfigAttr,详细字段含义及取值详见kernel\include\los_perf.h。
......@@ -53,6 +37,7 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
2. 采样数据缓冲区为环形buffer,buffer中读过的区域可以覆盖写,未被读过的区域不能被覆盖写。
3. 缓冲区有限,用户可通过注册水线到达的钩子进行buffer溢出提醒或buffer读操作。默认水线值为buffer总大小的1/2。 示例如下:
```
VOID Example_PerfNotifyHook(VOID)
{
......@@ -66,6 +51,7 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
```
4. 若perf采样的buffer涉及到cpu 跨cache,则用户可通过注册刷cache的钩子,进行cache同步。 示例如下:
```
VOID Example_PerfFlushHook(VOID *addr, UINT32 size)
{
......@@ -88,6 +74,7 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
- write: 用户态采样事件配置
- ioctl: 用户态Perf控制操作,包括
```
#define PERF_IOC_MAGIC 'T'
#define PERF_START _IO(PERF_IOC_MAGIC, 1)
......@@ -110,7 +97,7 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
1. 配置Perf模块相关宏。
配置Perf控制宏LOSCFG_KERNEL_PERF,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel-&gt;Enable Perf Feature"中打开:
| 配置项 | menuconfig选项 | 含义 | 设置值 |
| 配置项 | menuconfig选项 | 含义 | 设置值 |
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_PERF | Enable&nbsp;Perf&nbsp;Feature | Perf模块的裁剪开关 | YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Tick | Perf计时单位为tick | YES/NO |
......@@ -155,7 +142,8 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
前提条件:在menuconfig菜单中完成perf模块的配置。
实例代码如下:
实例代码如下:
```
#include "los_perf.h"
STATIC VOID OsPrintBuff(const CHAR *buf, UINT32 num)
......@@ -240,7 +228,8 @@ LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
### 内核态结果验证
输出结果如下:
输出结果如下:
```
--------count mode----------
[EMG] [cycles] eventType: 0xff: 5466989440
......@@ -290,6 +279,7 @@ hex: 00 ef ef ef 00 00 00 00 14 00 00 00 60 00 00 00 00 00 00 00 70 88 36 40 08
./perf list 查看可使用的事件列表, 输出如下:
```
cycles [Hardware event]
instruction [Hardware event]
......@@ -308,6 +298,7 @@ mux-pend [Software event]
./perf stat -e cycles os_dump, 输出如下:
```
type: 0
events[0]: 255, 0xffff
......@@ -325,6 +316,7 @@ time used: 0.058000(s)
./perf record -e cycles os_dump, 输出如下:
```
type: 0
events[0]: 255, 0xffff
......@@ -361,7 +353,8 @@ save perf data success at /storage/data/perf.data
### 用户态示例代码
实例代码如下:
实例代码如下:
```
#include "fcntl.h"
#include "user_copy.h"
......@@ -431,7 +424,8 @@ int main(int argc, char **argv)
### 用户态结果验证
输输出结果如下:出结果如下:
输出结果如下
```
[EMG] dump section data, addr: 0x8000000 length: 0x800000
num: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ...
......
# Trace调测
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [接口说明](#接口说明)
- [开发指导](#开发指导)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [示例代码](#示例代码)
- [结果验证](#结果验证)
## 基本概念
......@@ -33,19 +25,15 @@ Trace提供2种工作模式,离线模式和在线模式。
OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** Trace模块接口说明
**表1** Trace模块接口说明
| 功能分类 | 接口名 | 描述 |
| -------- | -------- | -------- |
| 启停控制 | LOS_TraceStart | 启动Trace |
| | LOS_TraceStop | 停止Trace |
| 操作Trace记录的数据 | LOS_TraceRecordDump | 输出Trace缓冲区数据 |
| | LOS_TraceRecordGet | 获取Trace缓冲区的首地址 |
| | LOS_TraceReset | 清除Trace缓冲区中的事件 |
| 过滤Trace记录的数据 | LOS_TraceEventMaskSet | 设置事件掩码,仅记录某些模块的事件 |
| 屏蔽某些中断号事件 | LOS_TraceHwiFilterHookReg | 注册过滤特定中断号事件的钩子函数 |
| 插桩函数 | LOS_TRACE_EASY | 简易插桩 |
| | LOS_TRACE | 标准插桩 |
| 功能分类 | 接口名 |
| -------- | -------- |
| 启停控制 | -&nbsp;LOS_TraceStart:启动Trace<br/>-&nbsp;LOS_TraceStop:停止Trace |
| 操作Trace记录的数据 | -&nbsp;LOS_TraceRecordDump:输出Trace缓冲区数据<br/>-&nbsp;LOS_TraceRecordGet:获取Trace缓冲区的首地址<br/>-&nbsp;LOS_TraceReset:清除Trace缓冲区中的事件 |
| 过滤Trace记录的数据 | LOS_TraceEventMaskSet:设置事件掩码,仅记录某些模块的事件 |
| 屏蔽某些中断号事件 | LOS_TraceHwiFilterHookReg:注册过滤特定中断号事件的钩子函数 |
| 插桩函数 | LOS_TRACE_EASY:简易插桩<br/>LOS_TRACE:标准插桩 |
- 当用户需要针对自定义事件进行追踪时,可按规则在目标源代码中进行插桩,系统提供如下2种插桩接口:
- LOS_TRACE_EASY(TYPE, IDENTITY, params...) 简易插桩。
......@@ -53,45 +41,49 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
- TYPE有效取值范围为[0, 0xF],表示不同的事件类型,不同取值表示的含义由用户自定义。
- IDENTITY类型UINTPTR,表示事件操作的主体对象。
- Params类型UINTPTR,表示事件的参数。
- 示例:
- 对文件fd读写操作的简易插桩示例:
```
假设需要新增对文件(fd1、fd2)读写操作的简易插桩,
自定义读操作为type:1, 写操作为type:2,则
在读fd1文件的适当位置插入:
LOS_TRACE_EASY(1, fd1, flag, size);
在读fd2文件的适当位置插入:
LOS_TRACE_EASY(1, fd2, flag, size);
在写fd1文件的适当位置插入:
LOS_TRACE_EASY(2, fd1, flag, size);
在写fd2文件的适当位置插入:
LOS_TRACE_EASY(2, fd2,flag, size);
/* 假设自定义读操作为type: 1, 写操作为type: 2 */
LOS_TRACE_EASY(1, fd, flag, size); /* 在读fd文件的适当位置插入 */
LOS_TRACE_EASY(2, fd, flag, size); /* 在写fd文件的适当位置插入 */
```
- LOS_TRACE(TYPE, IDENTITY, params...) 标准插桩。
- 相比简易插桩,支持动态过滤事件和参数裁剪,但使用上需要用户按规则来扩展。
- TYPE用于设置具体的事件类型,可以在头文件los_trace.h中的enum LOS_TRACE_TYPE中自定义事件类型。定义方法和规则可以参考其他事件类型。
- IDENTITY和Params的类型及含义同简易插桩。
- 示例:
1. 定义FS模块的类型,即FS模块的事件掩码
```
/* 在enum LOS_TRACE_MASK中定义, 定义规范为TRACE_#MOD#_FLAG, #MOD#表示模块名 */
TRACE_FS_FLAG = 0x4000
```
2. 定义FS模块的具体事件类型
```
/* 定义规范为#TYPE# = TRACE_#MOD#_FLAG | NUMBER, */
FS_READ = TRACE_FS_FLAG | 0; /* 读文件 */
FS_WRITE = TRACE_FS_FLAG | 1; /* 写文件 */
```
3. 定义事件参数
```
/* 定义规范为#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ... */
#define FS_READ_PARAMS(fp, fd, flag, size) fp, fd, flag, size /* 宏定义的参数对应于Trace缓冲区中记录的事件参数,用户可对任意参数字段进行裁剪 */
#define FS_READ_PARAMS(fp, fd, flag, size) /* 当定义为空时,表示不追踪该类型事件 */
```
4. 在目标代码中插桩
```
1.在enum LOS_TRACE_MASK中定义事件掩码,即模块级别的事件类型。
定义规范为TRACE_#MOD#_FLAG,#MOD#表示模块名。
例如:
TRACE_FS_FLAG = 0x4000
2.在enum LOS_TRACE_TYPE中定义具体事件类型。
定义规范为#TYPE# = TRACE_#MOD#_FLAG | NUMBER,
例如:
FS_READ = TRACE_FS_FLAG | 0; // 读文件
FS_WRITE = TRACE_FS_FLAG | 1; // 写文件
3.定义事件参数。定义规范为#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ...
其中的#TYPE#就是上面2中的#TYPE#,
例如:
#define FS_READ_PARAMS(fp, fd, flag, size) fp, fd, flag, size
宏定义的参数对应于Trace缓冲区中记录的事件参数,用户可对任意参数字段进行裁剪:
当定义为空时,表示不追踪该类型事件:
#define FS_READ_PARAMS(fp, fd, flag, size) // 不追踪文件读事件
4.在适当位置插入代码桩。
定义规范为LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...))
LOS_TRACE(FS_READ, fp, fd, flag, size); // 读文件的代码桩,
#TYPE#之后的入参就是上面3中的FS_READ_PARAMS函数的入参
/* 定义规范为LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...)) */
LOS_TRACE(FS_READ, fp, fd, flag, size); /* 读文件操作的代码桩 */
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
......@@ -106,7 +98,8 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
- Trace的典型操作流程为:LOS_TraceStart、 LOS_TraceStop、 LOS_TraceRecordDump.
- 针对中断事件的Trace, 提供中断号过滤,用于解决某些场景下特定中断号频繁触发导致其他事件被覆盖的情况,用户可自定义中断过滤的规则,
示例如下:
示例如下:
```
BOOL Example_HwiNumFilter(UINT32 hwiNum)
{
......@@ -129,8 +122,8 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
开启Trace调测的典型流程如下:
1. 配置Trace模块相关宏。
需要在target_config.h头文件中修改配置:
| 配置项 | 含义 | 设置值 |
需要在target_config.h头文件中修改配置:
| 配置项 | 含义 | 设置值 |
| -------- | -------- | -------- |
| LOSCFG_KERNEL_TRACE | Trace模块的裁剪开关 | YES/NO |
| LOSCFG_RECORDER_MODE_OFFLINE | Trace工作模式为离线模式 | YES/NO |
......@@ -185,6 +178,7 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
示例代码如下:
```
#include "los_trace.h"
UINT32 g_traceTestTaskId;
......@@ -235,6 +229,7 @@ UINT32 Example_Trace_test(VOID){
输出结果如下:
```
***TraceInfo begin***
clockFreq = 50000000
......@@ -263,6 +258,7 @@ Index Time(cycles) EventType CurTask Identity params
下面以序号为0的输出项为例,进行说明。
```
Index Time(cycles) EventType CurTask Identity params
0 0x366d5e88 0x45 0x1 0x0 0x1f 0x4
......@@ -274,12 +270,13 @@ Index Time(cycles) EventType CurTask Identity params
- Identity和params的含义需要查看TASK_SWITCH_PARAMS宏定义:
```
#define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \
taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus
```
因为\#TYPE\#_PARAMS(IDENTITY, parma1...) IDENTITY, ...,所以Identity为taskId(0x0),第一个参数为oldPriority(0x1f)
因为\#TYPE\#_PARAMS(IDENTITY, parma1...) IDENTITY, ...,所以Identity为taskId(0x0),第一个参数为oldPriority(0x1f)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> params的个数由LOSCFG_TRACE_FRAME_MAX_PARAMS配置,默认为3,超出的参数不会被记录,用户应自行合理配置该值。
......
# 内核概述
- [内核简介](#内核简介)
- [cpu体系架构支持](#cpu体系架构支持)
- [运行机制](#运行机制)
## 内核简介
......@@ -10,28 +7,29 @@ OpenHarmony LiteOS-M内核是面向IoT领域构建的轻量级物联网操作系
OpenHarmony LiteOS-M内核架构包含硬件相关层以及硬件无关层,如下图所示,其中硬件相关层按不同编译工具链、芯片架构分类,提供统一的HAL(Hardware Abstraction Layer)接口,提升了硬件易适配性,满足AIoT类型丰富的硬件和编译工具链的拓展;其他模块属于硬件无关层,其中基础内核模块提供基础能力,扩展模块提供网络、文件系统等组件能力,还提供错误处理、调测等能力,KAL(Kernel Abstraction Layer)模块提供统一的标准接口。
**图1** 内核架构图
![zh-cn_image_0000001199351155](figures/zh-cn_image_0000001199351155.png)
**图1** 内核架构图
![zh-cn_image_0000001199351155](figures/zh-cn_image_0000001199351155.png)
### cpu体系架构支持
### CPU体系架构支持
CPU体系架构分为通用架构定义和特定架构定义两层,通用架构定义层为所有体系架构都需要支持和实现的接口,特定架构定义层为特定体系架构所特有的部分。在新增一个体系架构的时候,必须需要实现通用架构定义层,如果该体系架构还有特有的功能,可以在特定架构定义层来实现。
**表1** CPU体系架构规则
**表1** CPU体系架构规则
| 规则 | 通用体系架构层 | 特定体系架构层 |
| 规则 | 通用体系架构层 | 特定体系架构层 |
| -------- | -------- | -------- |
| 头文件位置 | arch/include | arch/&lt;arch&gt;/&lt;arch&gt;/&lt;toolchain&gt;/ |
| 头文件命名 | los_&lt;function&gt;.h | los_arch_&lt;function&gt;.h |
| 函数命名 | Halxxxx | Halxxxx |
| 头文件位置 | arch/include | arch/&lt;arch&gt;/&lt;arch&gt;/&lt;toolchain&gt;/ |
| 头文件命名 | los_&lt;function&gt;.h | los_arch_&lt;function&gt;.h |
| 函数命名 | Halxxxx | Halxxxx |
LiteOS-M已经支持ARM Cortex-M3、ARM Cortex-M4、ARM Cortex-M7、ARM Cortex-M33、RISC-V等主流架构,如果需要扩展CPU体系架构,请参考[芯片架构适配点](../porting/porting-chip-kernel-overview.md#芯片架构适配点)
### 运行机制
在开发板配置文件target_config.h配置系统时钟、每秒Tick数,可以对任务、内存、IPC、异常处理模块进行裁剪配置。系统启动时,根据配置进行指定模块的初始化。内核启动流程包含外设初始化、系统时钟配置、内核初始化、操作系统启动等,详见内核启动流程
在开发板配置文件target_config.h配置系统时钟、每秒Tick数,可以对任务、内存、IPC、异常处理模块进行裁剪配置。系统启动时,根据配置进行指定模块的初始化。内核启动流程包含外设初始化、系统时钟配置、内核初始化、操作系统启动等,详见下图
**图2** 内核启动流程
![zh-cn_image_0000001160338832](figures/zh-cn_image_0000001160338832.png)
**图2** 内核启动流程
![zh-cn_image_0000001160338832](figures/zh-cn_image_0000001160338832.png)
# 轻量系统内核
- **[内核概述](kernel-mini-overview.md)**
- **[基础内核](kernel-mini-basic.md)**
......
# 位操作
- [基本概念](#基本概念)
- [功能说明](#功能说明)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [结果验证](#结果验证)
## 基本概念
......@@ -15,17 +10,13 @@
系统提供标志位的置1和清0操作,可以改变标志位的内容,同时还提供获取状态字中标志位为1的最高位和最低位的功能。用户也可以对系统的寄存器进行位操作。位操作模块为用户提供下面几种功能,接口详细信息可以查看API参考。
**表1** 位操作模块接口
**表1** 位操作模块接口
| **功能分类** | **接口名称** | **描述** |
| -------- | -------- | -------- |
| 置1/清0标志位 | LOS_BitmapSet | 对状态字的某一标志位进行置1操作 |
| | LOS_BitmapClr | 对状态字的某一标志位进行清0操作 |
| 获取标志位为1的bit位 | LOS_HighBitGet | 获取状态字中为1的最高位 |
| | LOS_LowBitGet | 获取状态字中为1的最低位 |
| 连续bit位操作 | LOS_BitmapSetNBits | 对状态字的连续标志位进行置1操作 |
| | LOS_BitmapClrNBits | 对状态字的连续标志位进行清0操作 |
| | LOS_BitmapFfz | 获取从最低有效位开始的第一个0的bit位 |
| **功能分类** | **接口描述** |
| -------- | -------- |
| 置1/清0标志位 | -&nbsp;LOS_BitmapSet:对状态字的某一标志位进行置1操作<br/>-&nbsp;LOS_BitmapClr:对状态字的某一标志位进行清0操作 |
| 获取标志位为1的bit位 | -&nbsp;LOS_HighBitGet:获取状态字中为1的最高位<br/>-&nbsp;LOS_LowBitGet:获取状态字中为1的最低位 |
| 连续bit位操作 | -&nbsp;LOS_BitmapSetNBits:对状态字的连续标志位进行置1操作<br/>-&nbsp;LOS_BitmapClrNBits:对状态字的连续标志位进行清0操作<br/>-&nbsp;LOS_BitmapFfz:获取从最低有效位开始的第一个0的bit位 |
## 编程实例
......@@ -43,6 +34,7 @@
4. 获取标志位为1的最低bit位。
```
#include "los_bitmap.h"
#include "los_printf.h"
......@@ -77,6 +69,7 @@ static UINT32 BitSample(VOID)
编译运行得到的结果为:
```
Bitmap Sample!
The flag is 0x10101010
......
# 双向链表
- [基本概念](#基本概念)
- [功能说明](#功能说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -14,30 +10,17 @@
双向链表模块为用户提供下面几种功能,接口详细信息可以查看API参考。
| **功能分类** | **接口名** | **描述** |
| -------- | -------- | -------- |
| 初始化链表 | LOS_ListInit | 将指定节点初始化为双向链表节点 |
| | LOS_DL_LIST_HEAD | 定义一个节点并初始化为双向链表节点 |
| 增加节点 | LOS_ListAdd | 将指定节点插入到双向链表头端 |
| | LOS_ListHeadInsert | 将指定节点插入到双向链表头端,同LOS_ListAdd |
| | LOS_ListTailInsert | 将指定节点插入到双向链表尾端 |
| 增加链表 | LOS_ListAddList | 将指定链表的头端插入到双向链表头端 |
| | LOS_ListHeadInsertList | 将指定链表的头端插入到双向链表头端,同LOS_ListAddList |
| | LOS_ListTailInsertList | 将指定链表的尾端插入到双向链表头端 |
| 删除节点 | LOS_ListDelete | 将指定节点从链表中删除 |
| | LOS_ListDelInit | 将指定节点从链表中删除,并使用该节点初始化链表 |
| 判断双向链表 | LOS_ListEmpty | 判断链表是否为空 |
| | LOS_DL_LIST_IS_END | 判断指定链表节点是否为链表尾端 |
| | LOS_DL_LIST_IS_ON_QUEUE | 判断链表节点是否在双向链表里 |
| 获取结构体信息 | LOS_OFF_SET_OF | 获取指定结构体内的成员相对于结构体起始地址的偏移量 |
| | LOS_DL_LIST_ENTRY | 获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称 |
| | LOS_ListPeekHeadType | 获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。 |
| | LOS_ListRemoveHeadType | 获取双向链表中第一个链表节点所在的结构体地址,并把第一个链表节点从链表中删除。接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。 |
| | LOS_ListNextType | 获取双向链表中指定链表节点的下一个节点所在的结构体地址。接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称。如果链表节点下一个为链表头结点为空,返回NULL。 |
| 遍历双向链表 | LOS_DL_LIST_FOR_EACH | 遍历双向链表 |
| | LOS_DL_LIST_FOR_EACH_SAFE | 遍历双向链表,并存储当前节点的后继节点用于安全校验 |
| 遍历包含双向链表的结构体 | LOS_DL_LIST_FOR_EACH_ENTRY | 遍历指定双向链表,获取包含该链表节点的结构体地址 |
| | LOS_DL_LIST_FOR_EACH_ENTRY_SAFE | 遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址 |
| | |
| -------- | -------- |
| **功能分类** | **接口名** |
| 初始化链表 | -&nbsp;LOS_ListInit:将指定节点初始化为双向链表节点<br/>-&nbsp;LOS_DL_LIST_HEAD:定义一个节点并初始化为双向链表节点 |
| 增加节点 | -&nbsp;LOS_ListAdd:将指定节点插入到双向链表头端<br/>-&nbsp;LOS_ListHeadInsert:将指定节点插入到双向链表头端,同LOS_ListAdd<br/>-&nbsp;LOS_ListTailInsert:将指定节点插入到双向链表尾端 |
| 增加链表 | -&nbsp;LOS_ListAddList:将指定链表的头端插入到双向链表头端<br/>-&nbsp;LOS_ListHeadInsertList:将指定链表的头端插入到双向链表头端<br/>-&nbsp;LOS_ListTailInsertList:将指定链表的尾端插入到双向链表头端 |
| 删除节点 | -&nbsp;LOS_ListDelete:将指定节点从链表中删除<br/>-&nbsp;LOS_ListDelInit:将指定节点从链表中删除,并使用该节点初始化链表 |
| 判断双向链表 | -&nbsp;LOS_ListEmpty:判断链表是否为空<br/>-&nbsp;LOS_DL_LIST_IS_END:判断指定链表节点是否为链表尾端:LOS_DL_LIST_IS_ON_QUEUE:判断链表节点是否在双向链表里 |
| 获取结构体信息 | -&nbsp;LOS_OFF_SET_OF:获取指定结构体内的成员相对于结构体起始地址的偏移量<br/>-&nbsp;LOS_DL_LIST_ENTRY:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称<br/>-&nbsp;LOS_ListPeekHeadType:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListRemoveHeadType:获取双向链表中第一个链表节点所在的结构体地址,并把第一个链表节点从链表中删除。接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListNextType:获取双向链表中指定链表节点的下一个节点所在的结构体地址。接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称。如果链表节点下一个为链表头结点为空,返回NULL。<br/>-&nbsp;LOS_OFF_SET_OF:获取指定结构体内的成员相对于结构体起始地址的偏移量<br/>-&nbsp;LOS_DL_LIST_ENTRY:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称<br/>-&nbsp;LOS_ListPeekHeadType:获取双向链表中第一个链表节点所在的结构体地址,接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListRemoveHeadType:获取双向链表中第一个链表节点所在的结构体地址,并把第一个链表节点从链表中删除。接口的第一个入参表示的是链表中的头节点,第二个入参是要获取的结构体名称,第三个入参是链表在该结构体中的名称。如果链表为空,返回NULL。<br/>-&nbsp;LOS_ListNextType:获取双向链表中指定链表节点的下一个节点所在的结构体地址。接口的第一个入参表示的是链表中的头节点,第二个入参是指定的链表节点,第三个入参是要获取的结构体名称,第四个入参是链表在该结构体中的名称。如果链表节点下一个为链表头结点为空,返回NULL。 |
| 遍历双向链表 | -&nbsp;LOS_DL_LIST_FOR_EACH:遍历双向链表<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_SAFE:遍历双向链表,并存储当前节点的后继节点用于安全校验 |
| 遍历包含双向链表的结构体 | -&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY:遍历指定双向链表,获取包含该链表节点的结构体地址<br/>-&nbsp;LOS_DL_LIST_FOR_EACH_ENTRY_SAFE:遍历指定双向链表,获取包含该链表节点的结构体地址,并存储包含当前节点的后继节点的结构体地址 |
## 开发流程
......@@ -82,6 +65,7 @@
4. 测试操作是否成功。
```
#include "stdio.h"
#include "los_list.h"
......@@ -127,8 +111,10 @@ static UINT32 ListSample(VOID)
编译运行得到的结果为:
```
Initial head Add listNode1 success
Initial head
Add listNode1 success
Tail insert listNode2 success
Delete success
```
# 标准库
- [标准库接口框架](#标准库接口框架)
- [操作实例](#操作实例)
- [与Linux标准库差异](#与linux标准库差异)
- [进程](#进程)
- [内存](#内存)
- [文件系统](#文件系统)
- [信号](#信号)
- [Time](#time)
OpenHarmony内核使用musl libc库,支持标准POSIX接口,开发者可基于POSIX标准接口开发内核之上的组件及应用。
## 标准库接口框架
**图1** POSIX接口框架
**图1** POSIX接口框架
![zh-cn_image_0000001172904117](figures/zh-cn_image_0000001172904117.png)
![zh-cn_image_0000001172904117](figures/zh-cn_image_0000001172904117.png)
musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony内核适配支持 ,以满足接口对外描述的功能要求。
......@@ -27,6 +19,7 @@ musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony
在本示例中,主线程创建了THREAD_NUM个子线程,每个子线程启动后等待被主线程唤醒,主线程成功唤醒所有子线程后,子线程继续执行直至生命周期结束,同时主线程通过pthread_join方法等待所有线程执行结束。
```
#include <stdio.h>
#include <unistd.h>
......@@ -229,6 +222,7 @@ mmap接口原型为:void \*mmap (void \*addr, size_t length, int prot, int fla
Linux目前支持的情况如下:
```
int main(int argc, char *argv[])
{
......@@ -252,7 +246,8 @@ int main(int argc, char *argv[])
```
OpenHarmony支持的情况如下:
OpenHarmony支持的情况如下:
```
int main(int argc, char *argv[])
{
......
# 基本数据结构
- **[双向链表](kernel-small-apx-dll.md)**
- **[位操作](kernel-small-apx-bitwise.md)**
\ No newline at end of file
# 附录
- **[基本数据结构](kernel-small-apx-structure.md)**
- **[标准库](kernel-small-apx-library.md)**
\ No newline at end of file
# 原子操作
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -48,34 +42,34 @@ OpenHarmony系统通过对ARMv6架构中的LDREX和STREX进行封装,向用户
OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** 原子操作接口说明
**表1** 原子操作接口说明
| 功能分类 | 接口**名称** | 描述 |
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 读 | LOS_AtomicRead | 读取32bit原子数据 |
| | LOS_Atomic64Read |读取64bit原子数据|
| 写 | LOS_AtomicSet | 设置32bit原子数据 |
| | LOS_Atomic64Set |设置64bit原子数据|
| 加 | LOS_AtomicAdd | 对32bit原子数据做加法 |
| | LOS_Atomic64Add |对64bit原子数据做加法|
| | LOS_AtomicInc |对32bit原子数据做加1|
| | LOS_Atomic64Inc |对64bit原子数据做加1|
| | LOS_AtomicIncRet |对32bit原子数据做加1并返回|
| | LOS_Atomic64IncRet |对64bit原子数据做加1并返回|
| 减 | LOS_AtomicSub | 对32bit原子数据做减法 |
| | LOS_Atomic64Sub |对64bit原子数据做减法|
| | LOS_AtomicDec |对32bit原子数据做减1|
| | LOS_Atomic64Dec |对64bit原子数据做减1|
| | LOS_AtomicDecRet |对32bit原子数据做减1并返回|
| | LOS_Atomic64DecRet |对64bit原子数据做减1并返回|
| 交换 | LOS_AtomicXchgByte | 交换8bit内存数据 |
| | LOS_AtomicXchg16bits |交换16bit内存数据|
| | LOS_AtomicXchg32bits |交换32bit内存数据|
| | LOS_AtomicXchg64bits |交换64bit内存数据|
| 先比较后交换 | LOS_AtomicCmpXchgByte | 比较相同后交换8bit内存数据 |
| | LOS_AtomicCmpXchg16bits |比较相同后交换16bit内存数据|
| | LOS_AtomicCmpXchg32bits |比较相同后交换32bit内存数据|
| | LOS_AtomicCmpXchg64bits |比较相同后交换64bit内存数据|
| 读 | LOS_AtomicRead | 读取32bit原子数据 |
| 读 | LOS_Atomic64Read | 读取64bit原子数据 |
| 写 | LOS_AtomicSet | 设置32bit原子数据 |
| 写 | LOS_Atomic64Set | 设置64bit原子数据 |
| 加 | LOS_AtomicAdd | 对32bit原子数据做加法 |
| 加 | LOS_Atomic64Add | 对64bit原子数据做加法 |
| 加 | LOS_AtomicInc | 对32bit原子数据做加1 |
| 加 | LOS_Atomic64Inc | 对64bit原子数据做加1 |
| 加 | LOS_AtomicIncRet | 对32bit原子数据做加1并返回 |
| 加 | LOS_Atomic64IncRet | 对64bit原子数据做加1并返回 |
| 减 | LOS_AtomicSub | 对32bit原子数据做减法 |
| 减 | LOS_Atomic64Sub | 对64bit原子数据做减法 |
| 减 | LOS_AtomicDec | 对32bit原子数据做减1 |
| 减 | LOS_Atomic64Dec | 对64bit原子数据做减1 |
| 减 | LOS_AtomicDecRet | 对32bit原子数据做减1并返回 |
| 减 | LOS_Atomic64DecRet | 对64bit原子数据做减1并返回 |
| 交换 | LOS_AtomicXchgByte | 交换8bit内存数据 |
| 交换 | LOS_AtomicXchg16bits | 交换16bit内存数据 |
| 交换 | LOS_AtomicXchg32bits | 交换32bit内存数据 |
| 交换 | LOS_AtomicXchg64bits | 交换64bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchgByte | 比较相同后交换8bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchg16bits | 比较相同后交换16bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchg32bits | 比较相同后交换32bit内存数据 |
| 先比较后交换 | LOS_AtomicCmpXchg64bits | 比较相同后交换64bit内存数据 |
### 开发流程
......@@ -102,6 +96,7 @@ OpenHarmony LiteOS-A内核的原子操作模块提供下面几种功能,接口
示例代码如下:
```
#include "los_hwi.h"
#include "los_atomic.h"
......@@ -164,6 +159,7 @@ UINT32 Example_AtomicTaskEntry(VOID)
**结果验证**
```
g_sum = 0
```
# 虚实映射
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
## 基本概念
虚实映射是指系统通过内存管理单元(MMU,Memory Management Unit)将进程空间的虚拟地址与实际的物理地址做映射,并指定相应的访问权限、缓存属性等。程序执行时,CPU访问的是虚拟内存,通过MMU页表条目找到对应的物理内存,并做相应的代码执行或数据读写操作。MMU的映射由页表(Page Table)来描述,其中保存虚拟地址和物理地址的映射关系以及访问权限等。每个进程在创建的时候都会创建一个页表,页表由一个个页表条目(Page Table Entry, PTE)构成,每个页表条目描述虚拟地址区间与物理地址区间的映射关系。MMU中有一块页表缓存,称为快表(TLB, Translation Lookaside Buffers),做地址转换时,MMU首先在TLB中查找,如果找到对应的页表条目可直接进行转换,提高了查询效率。CPU访问内存或外设的示意图如下:
**图1** CPU访问内存或外设的示意图
![zh-cn_image_0000001133263576](figures/zh-cn_image_0000001133263576.png)
**图1** CPU访问内存或外设的示意图
![zh-cn_image_0000001133263576](figures/zh-cn_image_0000001133263576.png)
## 运行机制
......@@ -24,8 +20,9 @@
- 若CPU访问已缓存至TLB的页表条目,无需再访问保存在内存中的页表,可加快查找速度。
**图2** CPU访问内存示意图
![zh-cn_image_0000001179103451](figures/zh-cn_image_0000001179103451.png)
**图2** CPU访问内存示意图
![zh-cn_image_0000001179103451](figures/zh-cn_image_0000001179103451.png)
## 开发指导
......@@ -33,15 +30,16 @@
### 接口说明
**表1** 虚实映射模块接口
**表1** MMU相关操作
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_ArchMmuQuery | 获取进程空间虚拟地址对应的物理地址以及映射属性。 |
| LOS_ArchMmuMap | 映射进程空间虚拟地址区间与物理地址区间。 |
| LOS_ArchMmuUnmap | 解除进程空间虚拟地址区间与物理地址区间的映射关系。 |
| LOS_ArchMmuChangeProt | 修改进程空间虚拟地址区间的映射属性。 |
| LOS_ArchMmuMove | 将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。 |
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| MMU相关操作 | LOS_ArchMmuQuery | 获取进程空间虚拟地址对应的物理地址以及映射属性。 |
| | LOS_ArchMmuMap |映射进程空间虚拟地址区间与物理地址区间。|
| | LOS_ArchMmuUnmap |解除进程空间虚拟地址区间与物理地址区间的映射关系。|
| | LOS_ArchMmuChangeProt |修改进程空间虚拟地址区间的映射属性。|
| | LOS_ArchMmuMove |将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。|
### 开发流程
......
# 中断及异常处理
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 基本概念
......@@ -23,8 +16,9 @@
以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。
**图1** 中断向量表
![zh-cn_image_0000001199713709](figures/zh-cn_image_0000001199713709.png)
**图1** 中断向量表
![zh-cn_image_0000001199713709](figures/zh-cn_image_0000001199713709.png)
## 开发指导
......@@ -34,14 +28,11 @@
异常处理为内部机制,不对外提供接口,中断模块提供对外接口如下:
| 功能分类 | **接口名称** | **描述** |
| -------- | -------- | -------- |
| 创建和删除中断 | LOS_HwiCreate | 中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序 |
| | LOS_HwiDelete |删除中断|
| 打开和关闭所有中断 | LOS_IntUnLock | 打开当前处理器所有中断响应 |
| | LOS_IntLock |关闭当前处理器所有中断响应|
| | LOS_IntRestore |恢复到使用LOS_IntLock关闭所有中断之前的状态|
| 获取系统支持的最大中断数 | LOS_GetSystemHwiMaximum | 获取系统支持的最大中断数 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 创建和删除中断 | -&nbsp;LOS_HwiCreate:中断创建,注册中断号、中断触发模式、中断优先级、中断处理程序。中断被触发时,会调用该中断处理程序<br/>-&nbsp;LOS_HwiDelete:删除中断 |
| 打开和关闭所有中断 | -&nbsp;LOS_IntUnLock:打开当前处理器所有中断响应<br/>-&nbsp;LOS_IntLock:关闭当前处理器所有中断响应<br/>-&nbsp;LOS_IntRestore:恢复到使用LOS_IntLock关闭所有中断之前的状态 |
| 获取系统支持的最大中断数 | LOS_GetSystemHwiMaximum:获取系统支持的最大中断数 |
### 开发流程
......@@ -65,6 +56,7 @@
代码实现如下,演示如何创建中断和删除中断,当指定的中断号HWI_NUM_TEST产生中断时,会调用中断处理函数:
```
#include "los_hwi.h"
/*中断处理函数*/
......@@ -110,6 +102,7 @@ static UINT32 Example_Interrupt(VOID)
编译运行得到的结果为:
```
Hwi create success!
Hwi delete success!
......
# 堆内存管理
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [使用场景](#使用场景)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 基本概念
......@@ -18,21 +10,21 @@
堆内存管理,即在内存资源充足的情况下,根据用户需求,从系统配置的一块比较大的连续内存(内存池,也是堆内存)中分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。与静态内存相比,动态内存管理的优点是按需分配,缺点是内存池中容易出现碎片。OpenHarmony LiteOS-A堆内存在TLSF算法的基础上,对区间的划分进行了优化,获得更优的性能,降低了碎片率。动态内存核心算法框图如下:
**图1** 小型系统动态内存核心算法
![zh-cn_image_0000001146437734](figures/zh-cn_image_0000001146437734.png)
**图1** 小型系统动态内存核心算法
![zh-cn_image_0000001146437734](figures/zh-cn_image_0000001146437734.png)
$$根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:[4, 127]和[2^{7}$, 2^{31}$],如上图size class所示:
根据空闲内存块的大小,使用多个空闲链表来管理。根据内存空闲块大小分为两个部分:[4, 127]和[2<sup>7</sup>, 2<sup>31</sup>],如上图size class所示:
1. 对[4,127]区间的内存进行等分,如图1下半部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。[4,127]区间的31个小区间内存对应31个比特位进行标记链表是否为空。
1. 对[4,127]区间的内存进行等分,如上图下半部分所示,分为31个小区间,每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位,值为1时,空闲链表非空。[4,127]区间的31个小区间内存对应31个比特位进行标记链表是否为空。
2. 大于127字节的空闲内存块,按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间,每个小区间又等分为8个二级小区间,见图1上半部分的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。总共24\*8=192个二级小区间,对应192个空闲链表和192个比特位进行标记链表是否为空。
2. 大于127字节的空闲内存块,按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间,每个小区间又等分为8个二级小区间,见上图上半部分的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。总共24\*8=192个二级小区间,对应192个空闲链表和192个比特位进行标记链表是否为空。
例如,当有40字节的空闲内存需要插入空闲链表时,对应小区间[40,43],第10个空闲链表,位图标记的第10比特位。把40字节的空闲内存挂载第10个空闲链表上,并判断是否需要更新位图标记。当需要申请40字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。当有580字节的空闲内存需要插入空闲链表时,对应二级小区间[2^9,2^9+2^6],第31+2\*8=47个空闲链表,并使用位图的第47个比特位来标记链表是否为空。把580字节的空闲内存挂载第47个空闲链表上,并判断是否需要更新位图标记。当需要申请580字节的内存时,根据位图标记获取存在满足申请大小的内存块的空闲链表,从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小,进行分割节点操作,剩余的节点重新挂载到相应的空闲链表上。如果对应的空闲链表为空,则向更大的内存区间去查询是否有满足条件的空闲链表,实际计算时,会一次性查找到满足申请大小的空闲链表。
内存管理结构如图2所示:
内存管理结构如下图所示:
**图2** 小型系统动态内存管理结构图
![zh-cn_image_0000001180855455](figures/zh-cn_image_0000001180855455.png)
**图2** 小型系统动态内存管理结构图
![zh-cn_image_0000001180855455](figures/zh-cn_image_0000001180855455.png)
- 内存池池头部分
内存池池头部分包含内存池信息、位图标记数组和空闲链表数组。内存池信息包含内存池起始地址及堆区域总大小,内存池属性。位图标记数组有7个32位无符号整数组成,每个比特位标记对应的空闲链表是否挂载空闲内存块节点。空闲内存链表包含223个空闲内存头节点信息,每个空闲内存头节点信息维护内存节点头和空闲链表中的前驱、后继空闲内存节点。
......@@ -53,22 +45,15 @@ $$根据空闲内存块的大小,使用多个空闲链表来管理。根据内
OpenHarmony LiteOS-A的堆内存管理主要为用户提供以下功能,接口详细信息可以查看API参考。
**表1** 堆内存管理接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 初始化和删除内存池 | LOS_MemInit | 初始化一块指定的动态内存池,大小为size |
| | LOS_MemDeInit |删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效|
| 申请、释放动态内存 | LOS_MemAlloc | 从指定动态内存池中申请size长度的内存 |
| | LOS_MemFree |释放从指定动态内存中申请的内存|
| | LOS_MemRealloc |按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块|
| | LOS_MemAllocAlign |从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存|
| 获取内存池信息 | LOS_MemPoolSizeGet | 获取指定动态内存池的总大小 |
| | LOS_MemTotalUsedGet |获取指定动态内存池的总使用量大小|
| | LOS_MemInfoGet |获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小|
| | LOS_MemPoolList |打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效|
| 获取内存块信息 | LOS_MemFreeNodeShow | 打印指定内存池的空闲内存块的大小及数量 |
| 检查指定内存池的完整性 | LOS_MemIntegrityCheck | 对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效 |
**表1** 堆内存管理接口
| 功能分类 | 接口描述 |
| -------- | -------- |
| 初始化和删除内存池 | -&nbsp;LOS_MemInit:初始化一块指定的动态内存池,大小为size<br/>-&nbsp;LOS_MemDeInit:删除指定内存池,仅打开LOSCFG_MEM_MUL_POOL时有效 |
| 申请、释放动态内存 | -&nbsp;LOS_MemAlloc:从指定动态内存池中申请size长度的内存<br/>-&nbsp;LOS_MemFree:释放从指定动态内存中申请的内存<br/>-&nbsp;LOS_MemRealloc:<br/>-&nbsp;按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块<br/>-&nbsp;LOS_MemAllocAlign:从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存 |
| 获取内存池信息 | -&nbsp;LOS_MemPoolSizeGet:获取指定动态内存池的总大小<br/>-&nbsp;LOS_MemTotalUsedGet:获取指定动态内存池的总使用量大小<br/>-&nbsp;LOS_MemInfoGet:获取指定内存池的内存结构信息,包括空闲内存大小、已使用内存大小、空闲内存块数量、已使用的内存块数量、最大的空闲内存块大小<br/>-&nbsp;LOS_MemPoolList:打印系统中已初始化的所有内存池,包括内存池的起始地址、内存池大小、空闲内存总大小、已使用内存总大小、最大的空闲内存块大小、空闲内存块数量、已使用的内存块数量。仅打开LOSCFG_MEM_MUL_POOL时有效 |
| 获取内存块信息 | LOS_MemFreeNodeShow:打印指定内存池的空闲内存块的大小及数量 |
| 检查指定内存池的完整性 | LOS_MemIntegrityCheck:对指定内存池做完整性检查,仅打开LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK时有效 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 由于动态内存管理需要管理控制块数据结构来管理内存,这些数据结构会额外消耗内存,故实际用户可使用内存总量小于配置项OS_SYS_MEM_SIZE的大小。
......@@ -106,6 +91,7 @@ OpenHarmony LiteOS-A的堆内存管理主要为用户提供以下功能,接口
示例代码如下:
```
#include "los_memory.h"
......@@ -176,6 +162,7 @@ UINT32 ExampleDynMemEntry(VOID)
输出结果如下:
```
Mem init success!
Mem alloc success!
......
# 物理内存管理
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [结果验证](#结果验证)
## 基本概念
......@@ -17,22 +10,24 @@
如下图所示,LiteOS-A内核的物理内存使用分布视图,主要由内核镜像、内核堆及物理页组成。内核堆部分见堆内存管理一节。
**图1** 物理内存使用分布图
![zh-cn_image_0000001179140185](figures/zh-cn_image_0000001179140185.png)
**图1** 物理内存使用分布图
![zh-cn_image_0000001222655518](figures/zh-cn_image_0000001222655518.png)
伙伴算法把所有空闲页帧分成9个内存块组,每组中内存块包含2的幂次方个页帧,例如:第0组的内存块包含2的0次方个页帧,即1个页帧;第8组的内存块包含2的8次方个页帧,即256个页帧。相同大小的内存块挂在同一个链表上进行管理。
- 申请内存
系统申请12KiB内存,即3个页帧时,9个内存块组中索引为3的链表挂着一块大小为8个页帧的内存块满足要求,分配出12KiB内存后还剩余20KiB内存,即5个页帧,将5个页帧分成2的幂次方之和,即4跟1,尝试查找伙伴进行合并。4个页帧的内存块没有伙伴则直接插到索引为2的链表上,继续查找1个页帧的内存块是否有伙伴,索引为0的链表上此时有1个,如果两个内存块地址连续则进行合并,并将内存块挂到索引为1的链表上,否则不做处理。
**图2** 内存申请示意图
![zh-cn_image_0000001189778871](figures/zh-cn_image_0000001189778871.png)
**图2** 内存申请示意图
![zh-cn_image_0000001189778871](figures/zh-cn_image_0000001189778871.png)
- 释放内存
系统释放12KiB内存,即3个页帧,将3个页帧分成2的幂次方之和,即2跟1,尝试查找伙伴进行合并,索引为1的链表上有1个内存块,若地址连续则合并,并将合并后的内存块挂到索引为2的链表上,索引为0的链表上此时也有1个,如果地址连续则进行合并,并将合并后的内存块挂到索引为1的链表上,此时继续判断是否有伙伴,重复上述操作。
**图3** 内存释放示意图
![zh-cn_image_0000001143739220](figures/zh-cn_image_0000001143739220.png)
**图3** 内存释放示意图
![zh-cn_image_0000001143739220](figures/zh-cn_image_0000001143739220.png)
## 开发指导
......@@ -40,18 +35,13 @@
### 接口说明
**表1** 物理内存管理模块接口
**表1** 物理内存管理模块接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 申请物理内存 | LOS_PhysPageAlloc | 申请一个物理页 |
| | LOS_PhysPagesAlloc |申请物理页并挂在对应的链表上|
| | LOS_PhysPagesAllocContiguous |申请多页地址连续的物理内存|
| 释放物理内存 | LOS_PhysPageFree | 释放一个物理页 |
| | LOS_PhysPagesFree |释放挂在链表上的物理页|
| | LOS_PhysPagesFreeContiguous |释放多页地址连续的物理内存|
| 查询地址 | LOS_VmPageGet | 根据物理地址获取其对应的物理页结构体指针 |
| | LOS_PaddrToKVaddr |根据物理地址获取其对应的内核虚拟地址|
| 功能分类 | 接口描述 |
| -------- | -------- |
| 申请物理内存 | -&nbsp;LOS_PhysPageAlloc:申请一个物理页<br/>-&nbsp;LOS_PhysPagesAlloc:申请物理页并挂在对应的链表上<br/>-&nbsp;LOS_PhysPagesAllocContiguous:申请多页地址连续的物理内存 |
| 释放物理内存 | -&nbsp;LOS_PhysPageFree:释放一个物理页<br/>-&nbsp;LOS_PhysPagesFree:释放挂在链表上的物理页<br/>-&nbsp;LOS_PhysPagesFreeContiguous:释放多页地址连续的物理内存 |
| 查询地址 | -&nbsp;LOS_VmPageGet:根据物理地址获取其对应的物理页结构体指针<br/>-&nbsp;LOS_PaddrToKVaddr:根据物理地址获取其对应的内核虚拟地址 |
### 开发流程
......@@ -70,6 +60,7 @@
编程示例主要是调用申请、释放接口对内存进行操作,包括申请一个页以及多个页的示例。
```
#include "los_vm_phys.h"
......@@ -176,6 +167,7 @@ UINT32 ExamplePhyMemCaseEntry(VOID)
编译运行得到的结果为:
```
LOS_PhysPagesAllocContiguous success
LOS_PhysPagesAlloc success
......
# 虚拟内存管理
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
## 基本概念
......@@ -12,7 +7,7 @@
系统将虚拟内存分割为称为虚拟页的内存块,大小一般为4KiB或64KiB,LiteOS-A内核默认的页的大小是4KiB,根据需要可以对MMU(Memory Management Units)进行配置。虚拟内存管理操作的最小单位就是一个页,LiteOS-A内核中一个虚拟地址区间region包含地址连续的多个虚拟页,也可只有一个页。同样,物理内存也会按照页大小进行分割,分割后的每个内存块称为页帧。虚拟地址空间划分:内核态占高地址3GiB(0x40000000 ~ 0xFFFFFFFF),用户态占低地址1GiB(0x01000000 ~ 0x3F000000),具体见下表,详细可以查看或配置los_vm_zone.h。
**表1** 内核态地址规划:
**表1** 内核态地址规划:
| Zone名称 | 描述 | 属性 |
| -------- | -------- | -------- |
......@@ -20,7 +15,7 @@
| Normal&nbsp;zone | 加载内核代码段、数据段、堆和栈的地址区间。 | Cache |
| high&nbsp;mem&nbsp;zone | 可以分配连续的虚拟内存,但其所映射的物理内存不一定连续。 | Cache |
**表2** 用户态虚地址规划:
**表2** 用户态虚地址规划:
| Zone名称 | 描述 | 属性 |
| -------- | -------- | -------- |
......@@ -38,8 +33,9 @@
- CPU访问的虚拟地址所在的页,如V2,没有与具体的物理页做映射,系统会触发缺页异常,系统申请一个物理页,并把相应的信息拷贝到物理页中,并且把物理页的起始地址更新到页表条目中。此时CPU重新执行访问虚拟内存的指令便能够访问到具体的代码或数据。
**图1** 内存映射示意图
![zh-cn_image_0000001179142959](figures/zh-cn_image_0000001179142959.png)
**图1** 内存映射示意图
![zh-cn_image_0000001179142959](figures/zh-cn_image_0000001179142959.png)
## 开发指导
......@@ -47,46 +43,73 @@
### 接口说明
**表3** 虚拟内存管理模块接口
**表3** 获取进程空间系列接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 获取进程空间系列接口 | LOS_CurrSpaceGet | 获取当前进程空间结构体指针 |
| | LOS_SpaceGet |获取虚拟地址对应的进程空间结构体指针|
| | LOS_GetKVmSpace |获取内核进程空间结构体指针|
| | LOS_GetVmallocSpace |获取vmalloc空间结构体指针|
| | LOS_GetVmSpaceList |获取进程空间链表指针|
| 虚拟地址区间region相关的操作 | LOS_RegionFind | 在进程空间内查找并返回指定地址对应的虚拟地址区间 |
| | LOS_RegionRangeFind |在进程空间内查找并返回指定地址范围对应的虚拟地址区间|
| | LOS_IsRegionFileValid |判断虚拟地址区间region是否与文件关联映射|
| | LOS_RegionAlloc |申请空闲的虚拟地址区间|
| | LOS_RegionFree |释放进程空间内特定的region|
| | LOS_RegionEndAddr |获取指定地址区间region的结束地址|
| | LOS_RegionSize |获取region的大小|
| | LOS_IsRegionTypeFile |判断是否为文件内存映射|
| | LOS_IsRegionPermUserReadOnly |判断地址区间是否是用户空间只读属性|
| | LOS_IsRegionFlagPrivateOnly |判断地址区间是否是具有私有属性|
| | LOS_SetRegionTypeFile |设置文件内存映射属性|
| | LOS_IsRegionTypeDev |判断是否为设备内存映射|
| | LOS_SetRegionTypeDev |设置设备内存映射属性|
| | LOS_IsRegionTypeAnon |判断是否为匿名映射|
| | LOS_SetRegionTypeAnon |设置匿名映射属性|
| 地址校验 | LOS_IsUserAddress | 判断地址是否在用户态空间 |
| | LOS_IsUserAddressRange |判断地址区间是否在用户态空间|
| | LOS_IsKernelAddress |判断地址是否在内核空间|
| | LOS_IsKernelAddressRange |判断地址区间是否在内核空间|
| | LOS_IsRangeInSpace |判断地址区间是否在进程空间内|
| vmalloc操作 | LOS_VMalloc | vmalloc申请内存 |
| | LOS_VFree |vmalloc释放内存|
| | LOS_IsVmallocAddress |判断地址是否是通过vmalloc申请的|
| 内存申请系列接口 | LOS_KernelMalloc | 当申请的内存小于16KiB时,系统从堆内存池分配内存;当申请的内存超过16KiB时,系统分配多个连续物理页用于内存分配 |
| | LOS_KernelMallocAlign |申请具有对齐属性的内存,申请规则同LOS_KernelMalloc接口|
| | LOS_KernelFree |释放由LOS_KernelMalloc和LOS_KernelMallocAlign接口申请的内存|
| | LOS_KernelRealloc |重新分配由LOS_KernelMalloc和LOS_KernelMallocAlign接口申请的内存|
| 其他 | LOS_PaddrQuery | 根据虚拟地址获取对应的物理地址 |
| | LOS_VmSpaceFree |释放进程空间,包括虚拟内存区间、页表等信息|
| | LOS_VmSpaceReserve |在进程空间中预留一块内存空间|
| | LOS_VaddrToPaddrMmap |将指定长度的物理地址区间与虚拟地址区间做映射,需提前申请物理地址区间|
| LOS_CurrSpaceGet | 获取当前进程空间结构体指针 |
| LOS_SpaceGet | 获取虚拟地址对应的进程空间结构体指针 |
| LOS_GetKVmSpace | 获取内核进程空间结构体指针 |
| LOS_GetVmallocSpace | 获取vmalloc空间结构体指针 |
| LOS_GetVmSpaceList | 获取进程空间链表指针 |
**表4** 虚拟地址区间region相关的操作
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_RegionFind | 在进程空间内查找并返回指定地址对应的虚拟地址区间 |
| LOS_RegionRangeFind | 在进程空间内查找并返回指定地址范围对应的虚拟地址区间 |
| LOS_IsRegionFileValid | 判断虚拟地址区间region是否与文件关联映射 |
| LOS_RegionAlloc | 申请空闲的虚拟地址区间 |
| LOS_RegionFree | 释放进程空间内特定的region |
| LOS_RegionEndAddr | 获取指定地址区间region的结束地址 |
| LOS_RegionSize | 获取region的大小 |
| LOS_IsRegionTypeFile | 判断是否为文件内存映射 |
| LOS_IsRegionPermUserReadOnly | 判断地址区间是否是用户空间只读属性 |
| LOS_IsRegionFlagPrivateOnly | 判断地址区间是否是具有私有属性 |
| LOS_SetRegionTypeFile | 设置文件内存映射属性 |
| LOS_IsRegionTypeDev | 判断是否为设备内存映射 |
| LOS_SetRegionTypeDev | 设置设备内存映射属性 |
| LOS_IsRegionTypeAnon | 判断是否为匿名映射 |
| LOS_SetRegionTypeAnon | 设置匿名映射属性 |
**表5** 地址校验
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_IsUserAddress | 判断地址是否在用户态空间 |
| LOS_IsUserAddressRange | 判断地址区间是否在用户态空间 |
| LOS_IsKernelAddress | 判断地址是否在内核空间 |
| LOS_IsKernelAddressRange | 判断地址区间是否在内核空间 |
| LOS_IsRangeInSpace | 判断地址区间是否在进程空间内 |
**表6** vmalloc操作
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_VMalloc | vmalloc申请内存 |
| LOS_VFree | vmalloc释放内存 |
| LOS_IsVmallocAddress | 判断地址是否是通过vmalloc申请的 |
**表7** 内存申请系列接口
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_KernelMalloc | 当申请的内存小于16KiB时,系统从堆内存池分配内存;当申请的内存超过16KiB时,系统分配多个连续物理页用于内存分配 |
| LOS_KernelMallocAlign | 申请具有对齐属性的内存,申请规则同LOS_KernelMalloc接口 |
| LOS_KernelFree | 释放由LOS_KernelMalloc和LOS_KernelMallocAlign接口申请的内存 |
| LOS_KernelRealloc | 重新分配由LOS_KernelMalloc和LOS_KernelMallocAlign接口申请的内存 |
**表8** 其他
| | |
| -------- | -------- |
| **接口名称** | **描述** |
| LOS_PaddrQuery | 根据虚拟地址获取对应的物理地址 |
| LOS_VmSpaceFree | 释放进程空间,包括虚拟内存区间、页表等信息 |
| LOS_VmSpaceReserve | 在进程空间中预留一块内存空间 |
| LOS_VaddrToPaddrMmap | 将指定长度的物理地址区间与虚拟地址区间做映射,需提前申请物理地址区间 |
### 开发流程
......
# 内存管理
- **[堆内存管理](kernel-small-basic-memory-heap.md)**
- **[物理内存管理](kernel-small-basic-memory-physical.md)**
......
# 进程
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
## 基本概念
......@@ -34,8 +29,9 @@
- 僵尸(Zombies):进程运行结束,等待父进程回收其控制块资源。
**图1** 进程状态迁移示意图
![zh-cn_image_0000001219007317](figures/zh-cn_image_0000001219007317.png)
**图1** 进程状态迁移示意图
![zh-cn_image_0000001219007317](figures/zh-cn_image_0000001219007317.png)
**进程状态迁移说明:**
......@@ -72,8 +68,9 @@ OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离,
进程只是资源管理单元,实际运行是由进程内的各个线程完成的,不同进程内的线程相互切换时会进行进程空间的切换。
**图2** 进程管理示意图
![zh-cn_image_0000001199736949](figures/zh-cn_image_0000001199736949.png)
**图2** 进程管理示意图
![zh-cn_image_0000001199736949](figures/zh-cn_image_0000001199736949.png)
## 开发指导
......@@ -81,22 +78,16 @@ OpenHarmony 提供的进程模块主要用于实现用户态进程的隔离,
### 接口说明
**表1** 进程管理模块接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 进程调度参数控制 | LOS_GetProcessScheduler | 获取指定进程的调度策略 |
| | LOS_SetProcessScheduler |设置指定进程的调度参数,包括优先级和调度策略|
| | LOS_GetProcessPriority |获取指定进程的优先级|
| | LOS_SetProcessPriority |设置指定进程的优先级|
| 等待回收子进程 | LOS_Wait | 等待子进程结束并回收子进程 |
| 进程组 | LOS_GetProcessGroupID | 获取指定进程的进程组ID |
| | LOS_GetCurrProcessGroupID |获取当前进程的进程组ID|
| 获取进程ID | LOS_GetCurrProcessID | 获取当前进程的进程ID |
| 用户及用户组 | LOS_GetUserID | 获取当前进程的用户ID |
| | LOS_GetGroupID |获取当前进程的用户组ID|
| | LOS_CheckInGroups |检查指定用户组ID是否在当前进程的用户组内|
| 系统支持的最大进程数 | LOS_GetSystemProcessMaximum | 获取系统支持的最大进程数目 |
**表1** 进程管理模块接口
| 功能分类 | 接口描述 |
| -------- | -------- |
| 进程调度参数控制 | -&nbsp;LOS_GetProcessScheduler:获取指定进程的调度策略<br/>-&nbsp;LOS_SetProcessScheduler:设置指定进程的调度参数,包括优先级和调度策略 |
| 等待回收子进程 | LOS_Wait:等待子进程结束并回收子进程 |
| 进程组 | -&nbsp;LOS_GetProcessGroupID:获取指定进程的进程组ID<br/>-&nbsp;LOS_GetCurrProcessGroupID:获取当前进程的进程组ID |
| 获取进程ID | LOS_GetCurrProcessID:获取当前进程的进程ID |
| 用户及用户组 | -&nbsp;LOS_GetUserID:获取当前进程的用户ID<br/>-&nbsp;LOS_GetGroupID:获取当前进程的用户组ID<br/>-&nbsp;LOS_CheckInGroups:检查指定用户组ID是否在当前进程的用户组内 |
| 系统支持的最大进程数 | LOS_GetSystemProcessMaximum:获取系统支持的最大进程数目 |
### 开发流程
......
# 调度器
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
## 基本概念
......@@ -21,13 +16,14 @@ OpenHarmony 调度的最小单元为线程。
OpenHarmony 采用进程优先级队列+线程优先级队列的方式,进程优先级范围为0-31,共有32个进程优先级桶队列,每个桶队列对应一个线程优先级桶队列;线程优先级范围也为0-31,一个线程优先级桶队列也有32个优先级队列。
**图1** 调度优先级桶队列示意图
![zh-cn_image_0000001199705711](figures/zh-cn_image_0000001199705711.png)
**图1** 调度优先级桶队列示意图
![zh-cn_image_0000001199705711](figures/zh-cn_image_0000001199705711.png)
OpenHarmony 在系统启动内核初始化之后开始调度,运行过程中创建的进程或线程会被加入到调度队列,系统根据进程和线程的优先级及线程的时间片消耗情况选择最优的线程进行调度运行,线程一旦调度到就会从调度队列上删除,线程在运行过程中发生阻塞,会被加入到对应的阻塞队列中并触发一次调度,调度其它线程运行。如果调度队列上没有可以调度的线程,则系统就会选择KIdle进程的线程进行调度运行。
**图2** 调度流程示意图
![zh-cn_image_0000001199706239](figures/zh-cn_image_0000001199706239.png)
**图2** 调度流程示意图
![zh-cn_image_0000001199706239](figures/zh-cn_image_0000001199706239.png)
## 开发指导
......@@ -35,7 +31,7 @@ OpenHarmony 在系统启动内核初始化之后开始调度,运行过程中
### 接口说明
| 功能分类 | 接口**名称** | 描述 |
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 触发系统调度 | LOS_Schedule | 触发系统调度 |
......
# 任务
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -33,8 +27,9 @@ OpenHarmony 内核的任务一共有32个优先级(0-31),最高优先级为0
- 退出(Exit):任务运行结束,等待父任务回收其控制块资源。
**图1** 任务状态迁移示意图
![zh-cn_image_0000001173399977](figures/zh-cn_image_0000001173399977.png)
**图1** 任务状态迁移示意图
![zh-cn_image_0000001173399977](figures/zh-cn_image_0000001173399977.png)
**任务状态迁移说明:**
......@@ -72,29 +67,16 @@ OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起
### 接口说明
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 任务的创建和删除 | LOS_TaskCreateOnly | 创建任务,并使该任务进入Init状态,不执行任务调度 |
| | LOS_TaskCreate |创建任务,并使该任务进入Ready状态,并调度|
| | LOS_TaskDelete |删除指定的任务|
| 任务状态控制 | LOS_TaskResume | 恢复挂起的任务 |
| | LOS_TaskSuspend |挂起指定的任务|
| | LOS_TaskJoin |挂起当前任务,等待指定任务运行结束并回收其任务控制块资源|
| | LOS_TaskDetach |修改任务的joinable属性为detach属性,detach属性的任务运行结束会自动回收任务控制块资源|
| | LOS_TaskDelay |任务延时等待|
| | LOS_TaskYield |显式放权,调整调用任务优先级的任务调度顺序|
| 任务调度的控制 | LOS_TaskLock | 锁任务调度 |
| | LOS_TaskUnlock |解锁任务调度|
| 任务优先级的控制 | LOS_CurTaskPriSet | 设置当前任务的优先级 |
| | LOS_TaskPriSet |设置指定任务的优先级|
| | LOS_TaskPriGet |获取指定任务的优先级|
| 任务信息获取 | LOS_CurTaskIDGet | 获取当前任务的ID |
| | LOS_TaskInfoGet |获取指定任务的信息|
| 任务绑核操作 | LOS_TaskCpuAffiSet | 绑定指定任务到指定cpu上运行,仅在多核下使用 |
| | LOS_TaskCpuAffiGet |获取指定任务的绑核信息,仅在多核下使用|
| 任务调度参数的控制 | LOS_GetTaskScheduler | 获取指定任务的调度策略 |
| | LOS_SetTaskScheduler |设置指定任务的调度参数,包括优先级和调度策略|
| 系统支持的最大任务数 | LOS_GetSystemTaskMaximum | 获取系统支持的最大任务数目 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 任务的创建和删除 | -&nbsp;LOS_TaskCreate:创建任务,并使该任务进入Init状态,不执行任务调度<br/>-&nbsp;LOS_TaskDelete:创建任务,并使该任务进入Ready状态,并调度<br/>-&nbsp;LOS_TaskDelete:删除指定的任务 |
| 任务状态控制 | -&nbsp;LOS_TaskResume:恢复挂起的任务<br/>-&nbsp;LOS_TaskSuspend:挂起指定的任务<br/>-&nbsp;LOS_TaskJoin:挂起当前任务,等待指定任务运行结束并回收其任务控制块资源<br/>-&nbsp;LOS_TaskDetach:修改任务的joinable属性为detach属性,detach属性的任务运行结束会自动回收任务控制块资源<br/>-&nbsp;LOS_TaskDelay:任务延时等待<br/>-&nbsp;LOS_TaskYield:显式放权,调整调用任务优先级的任务调度顺序 |
| 任务调度的控制 | -&nbsp;LOS_TaskLock:锁任务调度<br/>-&nbsp;LOS_TaskUnlock:解锁任务调度 |
| 任务优先级的控制 | -&nbsp;LOS_CurTaskPriSet:设置当前任务的优先级<br/>-&nbsp;LOS_TaskPriSet:设置指定任务的优先级<br/>-&nbsp;LOS_TaskPriGet:获取指定任务的优先级 |
| 任务信息获取 | -&nbsp;LOS_CurTaskIDGet:获取当前任务的ID<br/>-&nbsp;LOS_TaskInfoGet:获取指定任务的信息 |
| 任务绑核操作 | -&nbsp;LOS_TaskCpuAffiSet:绑定指定任务到指定cpu上运行,仅在多核下使用<br/>-&nbsp;LOS_TaskCpuAffiGet:获取指定任务的绑核信息,仅在多核下使用 |
| 任务调度参数的控制 | -&nbsp;LOS_GetTaskScheduler:获取指定任务的调度策略<br/>-&nbsp;LOS_SetTaskScheduler:设置指定任务的调度参数,包括优先级和调度策略 |
| 系统支持的最大任务数 | LOS_GetSystemTaskMaximum |
### 开发流程
......@@ -123,6 +105,7 @@ OpenHarmony 任务管理模块提供任务创建、任务延时、任务挂起
代码实现如下:
```
UINT32 g_taskLoID;
UINT32 g_taskHiID;
......@@ -225,6 +208,7 @@ UINT32 ExampleTaskCaseEntry(VOID)
编译运行得到的结果为:
```
LOS_TaskLock() Success!
ExampleTaskHi create Success!
......
# 进程管理
- **[进程](kernel-small-basic-process-process.md)**
- **[任务](kernel-small-basic-process-thread.md)**
......
# 软件定时器
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -63,15 +57,13 @@ OpenHarmony系统的软件定时器提供三类定时器机制:
OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接口详细信息可以查看API参考。
**表1** 软件定时器接口说明
**表1** 软件定时器接口说明
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 创建、删除定时器 | LOS_SwtmrCreate | 创建软件定时器 |
| | LOS_SwtmrDelete |删除软件定时器|
| 启动、停止定时器 | LOS_SwtmrStart | 启动软件定时器 |
| | LOS_SwtmrStop |停止软件定时器|
| 获得软件定时剩余Tick数 | LOS_SwtmrTimeGet | 获得软件定时器剩余Tick数 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 创建、删除定时器 | LOS_SwtmrCreate:创建软件定时器<br/>LOS_SwtmrDelete:删除软件定时器 |
| 启动、停止定时器 | LOS_SwtmrStart:启动软件定时器<br/>LOS_SwtmrStop:停止软件定时器 |
| 获得软件定时剩余Tick数 | LOS_SwtmrTimeGet:获得软件定时器剩余Tick数 |
### 开发流程
......@@ -117,7 +109,8 @@ OpenHarmony LiteOS-A内核的软件定时器模块提供下面几种功能,接
- 配置好OS_SWTMR_HANDLE_QUEUE_SIZE软件定时器队列最大长度。
**编程示例**
**编程示例**
```
#include "los_swtmr.h"
......@@ -183,6 +176,7 @@ void Timer_example(void)
**运行结果**
```
create Timer1 success
start Timer1 success
......
# 时间管理
- [基本概念](#基本概念)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -30,14 +25,12 @@ OpenHarmony系统的时间管理模块提供时间转换、统计、延迟功能
OpenHarmony LiteOS-A内核的时间管理提供下面几种功能,接口详细信息可以查看API参考。
**表1** 时间管理相关接口说明
**表1** 时间管理相关接口说明
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 时间转换 | LOS_MS2Tick | 毫秒转换成Tick |
| | LOS_Tick2MS |Tick转换成毫秒|
| 时间统计 | LOS_TickCountGet | 获取当前Tick数 |
| | LOS_CyclePerTickGet |每个Tick的cycle数|
| 功能分类 | 接口描述 |
| -------- | -------- |
| 时间转换 | LOS_MS2Tick:毫秒转换成Tick<br/>LOS_Tick2MS:Tick转换成毫秒 |
| 时间统计 | LOS_TickCountGet:获取当前Tick数<br/>LOS_CyclePerTickGet:每个Tick的cycle数 |
### 开发流程
......@@ -64,7 +57,8 @@ OpenHarmony LiteOS-A内核的时间管理提供下面几种功能,接口详细
**示例代码**
时间转换:
时间转换:
```
VOID Example_TransformTime(VOID)
{
......@@ -79,6 +73,7 @@ VOID Example_TransformTime(VOID)
时间统计和时间延迟:
```
VOID Example_GetTime(VOID)
{
......@@ -111,6 +106,7 @@ VOID Example_GetTime(VOID)
时间转换:
```
uwTick = 10000
uwMs = 100
......@@ -118,6 +114,7 @@ uwMs = 100
时间统计和时间延迟:
```
LOS_CyclePerTickGet = 49500
LOS_TickCountGet = 5042
......
# 事件
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [事件控制块](#事件控制块)
- [事件运作原理](#事件运作原理)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [编程示例](#编程示例)
- [结果验证](#结果验证)
## 基本概念
......@@ -42,6 +31,7 @@ OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点:
### 事件控制块
```
/**
* 事件控制块数据结构
......@@ -73,8 +63,8 @@ typedef struct tagEvent {
**事件销毁**:销毁指定的事件控制块。
**图1** 小型系统事件运作原理图
![zh-cn_image_0000001180952545](figures/zh-cn_image_0000001180952545.png)
**图1** 小型系统事件运作原理图
![zh-cn_image_0000001180952545](figures/zh-cn_image_0000001180952545.png)
## 开发指导
......@@ -84,16 +74,15 @@ typedef struct tagEvent {
OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。
**表1** 事件模块接口
**表1** 事件模块接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 初始化事件 | LOS_EventInit | 初始化一个事件控制块 |
| 读/写事件 | LOS_EventRead | 读取指定事件类型,超时时间为相对时间:单位为Tick |
| | LOS_EventWrite |写指定的事件类型|
| 清除事件 | LOS_EventClear | 清除指定的事件类型 |
| 校验事件掩码 | LOS_EventPoll | 根据用户传入的事件ID、事件掩码及读取模式,返回用户传入的事件是否符合预期 |
| 销毁事件 | LOS_EventDestroy | 销毁指定的事件控制块 |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 初始化事件 | LOS_EventInit:初始化一个事件控制块 |
| 读/写事件 | -&nbsp;LOS_EventRead:读取指定事件类型,超时时间为相对时间:单位为Tick<br/>-&nbsp;LOS_EventWrite:写指定的事件类型 |
| 清除事件 | LOS_EventClear:清除指定的事件类型 |
| 校验事件掩码 | -&nbsp;LOS_EventPoll:根据用户传入的事件ID、事件掩码及读取模式,返回用户传入的事件是否符合预期<br/>-&nbsp;LOS_EventDestroy:销毁指定的事件控制块 |
| 销毁事件 | LOS_EventDestroy:销毁指定的事件控制块 |
### 开发流程
......@@ -140,6 +129,7 @@ OpenHarmony LiteOS-A内核的事件模块提供下面几种功能。
示例代码如下:
```
#include "los_event.h"
#include "los_task.h"
......@@ -224,6 +214,7 @@ UINT32 Example_EventEntry(VOID)
编译运行得到的结果为:
```
Example_Event wait event 0x1
Example_TaskEntry write event.
......
# 互斥锁
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
## 基本概念
......@@ -40,8 +34,8 @@
用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务如果想访问这个公共资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性。
**图1** 小型系统互斥锁运作示意图
![zh-cn_image_0000001177654887](figures/zh-cn_image_0000001177654887.png)
**图1** 小型系统互斥锁运作示意图
![zh-cn_image_0000001177654887](figures/zh-cn_image_0000001177654887.png)
## 开发指导
......@@ -49,26 +43,14 @@
### 接口说明
**表1** 互斥锁模块接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 初始化和销毁互斥锁 | LOS_MuxInit | 互斥锁初始化 |
| | LOS_MuxDestroy |销毁指定的互斥锁|
| 互斥锁的申请和释放 | LOS_MuxLock | 申请指定的互斥锁 |
| | LOS_MuxTrylock |尝试申请指定的互斥锁,不阻塞|
| | LOS_MuxUnlock |释放指定的互斥锁|
| 校验互斥锁 | LOS_MuxIsValid | 判断互斥锁释放有效 |
| 初始化和销毁互斥锁属性 | LOS_MuxAttrInit | 互斥锁属性初始化 |
| | LOS_MuxAttrDestroy |销毁指定的互斥锁属性|
| 设置和获取互斥锁属性 | LOS_MuxAttrGetType | 获取指定互斥锁属性的类型属性 |
| | LOS_MuxAttrSetType |设置指定互斥锁属性的类型属性|
| | LOS_MuxAttrGetProtocol |获取指定互斥锁属性的协议属性|
| | LOS_MuxAttrSetProtocol |设置指定互斥锁属性的协议属性|
| | LOS_MuxAttrGetPrioceiling |获取指定互斥锁属性的优先级上限属性|
| | LOS_MuxAttrSetPrioceiling |设置指定互斥锁属性的优先级上限属性|
| | LOS_MuxGetPrioceiling |获取互斥锁优先级上限属性|
| | LOS_MuxSetPrioceiling |设置互斥锁优先级上限属性|
**表1** 互斥锁模块接口
| 功能分类 | 接口描述 |
| -------- | -------- |
| 初始化和销毁互斥锁 | -&nbsp;LOS_MuxInit:互斥锁初始化<br/>-&nbsp;LOS_MuxDestroy:销毁指定的互斥锁 |
| 互斥锁的申请和释放 | -&nbsp;LOS_MuxLock:申请指定的互斥锁<br/>-&nbsp;LOS_MuxTrylock:尝试申请指定的互斥锁,不阻塞<br/>-&nbsp;LOS_MuxUnlock:释放指定的互斥锁 |
| 校验互斥锁 | -&nbsp;LOS_MuxIsValid:判断互斥锁释放有效<br/>-&nbsp;LOS_MuxAttrDestroy:销毁指定的互斥锁属性 |
| 设置和获取互斥锁属性 | -&nbsp;LOS_MuxAttrGetType:获取指定互斥锁属性的类型属性<br/>-&nbsp;LOS_MuxAttrSetType:设置指定互斥锁属性的类型属性<br/>-&nbsp;LOS_MuxAttrGetProtocol:获取指定互斥锁属性的协议属性<br/>-&nbsp;LOS_MuxAttrSetProtocol:设置指定互斥锁属性的协议属性<br/>-&nbsp;LOS_MuxAttrGetPrioceiling:获取指定互斥锁属性的优先级上限属性<br/>-&nbsp;LOS_MuxAttrSetPrioceiling:设置指定互斥锁属性的优先级上限属性<br/>-&nbsp;LOS_MuxGetPrioceiling:获取互斥锁优先级上限属性<br/>-&nbsp;LOS_MuxSetPrioceiling:设置互斥锁优先级上限属性 |
### 开发流程
......@@ -121,6 +103,7 @@
示例代码如下:
```
#include <string.h>
#include "los_mux.h"
......@@ -226,6 +209,7 @@ UINT32 Example_MutexEntry(VOID)
编译运行得到的结果为:
```
task1 try to get mutex, wait 10 ticks.
task2 try to get mutex, wait forever.
......
# 消息队列
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [队列控制块](#队列控制块)
- [队列运作原理](#队列运作原理)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [编程示例](#编程示例)
- [结果验证](#结果验证)
## 基本概念
队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。
可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将都队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性:
- 消息以先进先出的方式排队,支持异步读写。
- 读队列和写队列都支持超时机制。
- 每读取一条消息,就会将该消息节点设置为空闲。
- 发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。
- 一个任务能够从任意一个消息队列接收和发送消息。
- 多个任务能够从同一个消息队列接收和发送消息。
- 创建队列时所需的队列空间,接口内系统自行动态申请内存。
## 运行机制
### 队列控制块
```
/**
* 队列控制块数据结构
*/
typedef struct {
UINT8 *queueHandle; /**< Pointer to a queue handle */
UINT16 queueState; /**< Queue state */
UINT16 queueLen; /**< Queue length */
UINT16 queueSize; /**< Node size */
UINT32 queueID; /**< queueID */
UINT16 queueHead; /**< Node head */
UINT16 queueTail; /**< Node tail */
UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable */
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */
LOS_DL_LIST memList; /**< Pointer to the memory linked list */
} LosQueueCB;
```
每个队列控制块中都含有队列状态,表示该队列的使用情况:
- OS_QUEUE_UNUSED:队列未被使用。
- OS_QUEUE_INUSED:队列被使用中。
### 队列运作原理
- 创建队列时,创建队列成功会返回队列ID。
- 在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail,用于表示当前队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置。Tail表示被占用的消息节点的结束位置,也是空闲消息节点的起始位置。队列刚创建时,Head和Tail均指向队列起始位置。
- 写队列时,根据readWriteableCnt[1]判断队列是否可以写入,不能对已满(readWriteableCnt[1]为0)队列进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。
- 读队列时,根据readWriteableCnt[0]判断队列是否有消息需要读取,对全部空闲(readWriteableCnt[0]为0)队列进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。如果Head已经指向队列尾部则采用回卷方式。
- 删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态,并释放队列所占内存。
**图1** 队列读写数据操作示意图
![zh-cn_image_0000001132875772](figures/zh-cn_image_0000001132875772.png)
上图对读写队列做了示意,图中只画了尾节点写入方式,没有画头节点写入,但是两者是类似的。
## 开发指导
### 接口说明
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 创建/删除消息队列 | LOS_QueueCreate | 创建一个消息队列,由系统动态申请队列空间 |
| | LOS_QueueDelete |根据队列ID删除一个指定队列|
| 读/写队列(不带拷贝) | LOS_QueueRead | 读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址) |
| | LOS_QueueWrite |向指定队列尾节点中写入入参bufferAddr的值(即buffer的地址)|
| | LOS_QueueWriteHead |向指定队列头节点中写入入参bufferAddr的值(即buffer的地址)|
| 读/写队列(带拷贝) | LOS_QueueReadCopy | 读取指定队列头节点中的数据 |
| | LOS_QueueWriteCopy |向指定队列尾节点中写入入参bufferAddr中保存的数据|
| | LOS_QueueWriteHeadCopy |向指定队列头节点中写入入参bufferAddr中保存的数据|
| 获取队列信息 | LOS_QueueInfoGet | 获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务 |
### 开发流程
1. 用LOS_QueueCreate创建队列。创建成功后,可以得到队列ID。
2. 通过LOS_QueueWrite或者LOS_QueueWriteCopy写队列。
3. 通过LOS_QueueRead或者LOS_QueueReadCopy读队列。
4. 通过LOS_QueueInfoGet获取队列信息。
5. 通过LOS_QueueDelete删除队列。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 系统支持的最大队列数是指:整个系统的队列资源总个数,而非用户能使用的个数。例如:系统软件定时器多占用一个队列资源,那么用户能使用的队列资源就会减少一个。
>
> - 创建队列时传入的队列名和flags暂时未使用,作为以后的预留参数。
>
> - 队列接口函数中的入参timeOut是相对时间。
>
> - LOS_QueueReadCopy和LOS_QueueWriteCopy及LOS_QueueWriteHeadCopy是一组接口,LOS_QueueRead和LOS_QueueWrite及LOS_QueueWriteHead是一组接口,每组接口需要配套使用。
>
> - 鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,用户必须保证调用LOS_QueueRead获取到的指针所指向的内存区域在读队列期间没有被异常修改或释放,否则可能导致不可预知的后果。
>
# 消息队列
## 基本概念
队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。
可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将都队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用,可以使用队列实现任务异步通信,队列具有如下特性:
- 消息以先进先出的方式排队,支持异步读写。
- 读队列和写队列都支持超时机制。
- 每读取一条消息,就会将该消息节点设置为空闲。
- 发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。
- 一个任务能够从任意一个消息队列接收和发送消息。
- 多个任务能够从同一个消息队列接收和发送消息。
- 创建队列时所需的队列空间,接口内系统自行动态申请内存。
## 运行机制
### 队列控制块
```
/**
* 队列控制块数据结构
*/
typedef struct {
UINT8 *queueHandle; /**< Pointer to a queue handle */
UINT16 queueState; /**< Queue state */
UINT16 queueLen; /**< Queue length */
UINT16 queueSize; /**< Node size */
UINT32 queueID; /**< queueID */
UINT16 queueHead; /**< Node head */
UINT16 queueTail; /**< Node tail */
UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable */
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */
LOS_DL_LIST memList; /**< Pointer to the memory linked list */
} LosQueueCB;
```
每个队列控制块中都含有队列状态,表示该队列的使用情况:
- OS_QUEUE_UNUSED:队列未被使用。
- OS_QUEUE_INUSED:队列被使用中。
### 队列运作原理
- 创建队列时,创建队列成功会返回队列ID。
- 在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail,用于表示当前队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置。Tail表示被占用的消息节点的结束位置,也是空闲消息节点的起始位置。队列刚创建时,Head和Tail均指向队列起始位置。
- 写队列时,根据readWriteableCnt[1]判断队列是否可以写入,不能对已满(readWriteableCnt[1]为0)队列进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。
- 读队列时,根据readWriteableCnt[0]判断队列是否有消息需要读取,对全部空闲(readWriteableCnt[0]为0)队列进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。如果Head已经指向队列尾部则采用回卷方式。
- 删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态,并释放队列所占内存。
**图1** 队列读写数据操作示意图
![zh-cn_image_0000001132875772](figures/zh-cn_image_0000001132875772.png)
上图对读写队列做了示意,图中只画了尾节点写入方式,没有画头节点写入,但是两者是类似的。
## 开发指导
### 接口说明
| 功能分类 | 接口描述 |
| -------- | -------- |
| 创建/删除消息队列 | -&nbsp;LOS_QueueCreate:创建一个消息队列,由系统动态申请队列空间<br/>-&nbsp;LOS_QueueDelete:根据队列ID删除一个指定队列 |
| 读/写队列(不带拷贝) | -&nbsp;LOS_QueueRead:读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)<br/>-&nbsp;LOS_QueueWrite:向指定队列尾节点中写入入参bufferAddr的值(即buffer的地址)<br/>-&nbsp;LOS_QueueWriteHead:向指定队列头节点中写入入参bufferAddr的值(即buffer的地址) |
| 读/写队列(带拷贝) | -&nbsp;LOS_QueueReadCopy:读取指定队列头节点中的数据<br/>-&nbsp;LOS_QueueWriteCopy:向指定队列尾节点中写入入参bufferAddr中保存的数据<br/>-&nbsp;LOS_QueueWriteHeadCopy:向指定队列头节点中写入入参bufferAddr中保存的数据 |
| 获取队列信息 | LOS_QueueInfoGet:获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务 |
### 开发流程
1. 用LOS_QueueCreate创建队列。创建成功后,可以得到队列ID。
2. 通过LOS_QueueWrite或者LOS_QueueWriteCopy写队列。
3. 通过LOS_QueueRead或者LOS_QueueReadCopy读队列。
4. 通过LOS_QueueInfoGet获取队列信息。
5. 通过LOS_QueueDelete删除队列。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 系统支持的最大队列数是指:整个系统的队列资源总个数,而非用户能使用的个数。例如:系统软件定时器多占用一个队列资源,那么用户能使用的队列资源就会减少一个。
>
> - 创建队列时传入的队列名和flags暂时未使用,作为以后的预留参数。
>
> - 队列接口函数中的入参timeOut是相对时间。
>
> - LOS_QueueReadCopy和LOS_QueueWriteCopy及LOS_QueueWriteHeadCopy是一组接口,LOS_QueueRead和LOS_QueueWrite及LOS_QueueWriteHead是一组接口,每组接口需要配套使用。
>
> - 鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,用户必须保证调用LOS_QueueRead获取到的指针所指向的内存区域在读队列期间没有被异常修改或释放,否则可能导致不可预知的后果。
>
> - LOS_QueueRead和LOS_QueueReadCopy接口的读取长度如果小于消息实际长度,消息将被截断。
>
> - 鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,也就意味着实际写和读的消息长度仅仅是一个指针数据,因此用户使用这组接口之前,需确保创建队列时的消息节点大小,为一个指针的长度,避免不必要的浪费和读取失败。
## 编程实例
### 实例描述
创建一个队列,两个任务。任务1调用写队列接口发送消息,任务2通过读队列接口接收消息。
1. 通过LOS_TaskCreate创建任务1和任务2。
2. 通过LOS_QueueCreate创建一个消息队列。
3. 在任务1 SendEntry中发送消息。
4. 在任务2 RecvEntry中接收消息。
5. 通过LOS_QueueDelete删除队列。
### 编程示例
示例代码如下:
```
#include "los_task.h"
#include "los_queue.h"
static UINT32 g_queue;
#define BUFFER_LEN 50
VOID SendEntry(VOID)
{
UINT32 ret = 0;
CHAR abuf[] = "test message";
UINT32 len = sizeof(abuf);
ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0);
if(ret != LOS_OK) {
printf("send message failure, error: %x\n", ret);
}
}
VOID RecvEntry(VOID)
{
UINT32 ret = 0;
CHAR readBuf[BUFFER_LEN] = {0};
UINT32 readLen = BUFFER_LEN;
//休眠1s
usleep(1000000);
ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0);
if(ret != LOS_OK) {
printf("recv message failure, error: %x\n", ret);
}
printf("recv message: %s\n", readBuf);
ret = LOS_QueueDelete(g_queue);
if(ret != LOS_OK) {
printf("delete the queue failure, error: %x\n", ret);
}
printf("delete the queue success!\n");
}
UINT32 ExampleQueue(VOID)
{
printf("start queue example\n");
UINT32 ret = 0;
UINT32 task1, task2;
TSK_INIT_PARAM_S initParam = {0};
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry;
initParam.usTaskPrio = 9;
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
initParam.pcName = "SendQueue";
LOS_TaskLock();
ret = LOS_TaskCreate(&task1, &initParam);
if(ret != LOS_OK) {
printf("create task1 failed, error: %x\n", ret);
return ret;
}
initParam.pcName = "RecvQueue";
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry;
ret = LOS_TaskCreate(&task2, &initParam);
if(ret != LOS_OK) {
printf("create task2 failed, error: %x\n", ret);
return ret;
}
ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50);
if(ret != LOS_OK) {
printf("create queue failure, error: %x\n", ret);
}
printf("create the queue success!\n");
LOS_TaskUnlock();
return ret;
}
```
### 结果验证
编译运行得到的结果为:
```
start test example
create the queue success!
recv message: test message
delete the queue success!
```
>
> - 鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,也就意味着实际写和读的消息长度仅仅是一个指针数据,因此用户使用这组接口之前,需确保创建队列时的消息节点大小,为一个指针的长度,避免不必要的浪费和读取失败。
## 编程实例
### 实例描述
创建一个队列,两个任务。任务1调用写队列接口发送消息,任务2通过读队列接口接收消息。
1. 通过LOS_TaskCreate创建任务1和任务2。
2. 通过LOS_QueueCreate创建一个消息队列。
3. 在任务1 SendEntry中发送消息。
4. 在任务2 RecvEntry中接收消息。
5. 通过LOS_QueueDelete删除队列。
### 编程示例
示例代码如下:
```
#include "los_task.h"
#include "los_queue.h"
static UINT32 g_queue;
#define BUFFER_LEN 50
VOID SendEntry(VOID)
{
UINT32 ret = 0;
CHAR abuf[] = "test message";
UINT32 len = sizeof(abuf);
ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0);
if(ret != LOS_OK) {
printf("send message failure, error: %x\n", ret);
}
}
VOID RecvEntry(VOID)
{
UINT32 ret = 0;
CHAR readBuf[BUFFER_LEN] = {0};
UINT32 readLen = BUFFER_LEN;
//休眠1s
usleep(1000000);
ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0);
if(ret != LOS_OK) {
printf("recv message failure, error: %x\n", ret);
}
printf("recv message: %s\n", readBuf);
ret = LOS_QueueDelete(g_queue);
if(ret != LOS_OK) {
printf("delete the queue failure, error: %x\n", ret);
}
printf("delete the queue success!\n");
}
UINT32 ExampleQueue(VOID)
{
printf("start queue example\n");
UINT32 ret = 0;
UINT32 task1, task2;
TSK_INIT_PARAM_S initParam = {0};
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry;
initParam.usTaskPrio = 9;
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
initParam.pcName = "SendQueue";
LOS_TaskLock();
ret = LOS_TaskCreate(&task1, &initParam);
if(ret != LOS_OK) {
printf("create task1 failed, error: %x\n", ret);
return ret;
}
initParam.pcName = "RecvQueue";
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry;
ret = LOS_TaskCreate(&task2, &initParam);
if(ret != LOS_OK) {
printf("create task2 failed, error: %x\n", ret);
return ret;
}
ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50);
if(ret != LOS_OK) {
printf("create queue failure, error: %x\n", ret);
}
printf("create the queue success!\n");
LOS_TaskUnlock();
return ret;
}
```
### 结果验证
编译运行得到的结果为:
```
start test example
create the queue success!
recv message: test message
delete the queue success!
```
# 读写锁
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
## 基本概念
......@@ -37,18 +32,15 @@
### 接口说明
**表1** 读写锁模块接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 读写锁的创建和删除 | LOS_RwlockInit | 创建读写锁 |
| | LOS_RwlockDestroy |删除指定的读写锁|
| 读模式下的锁的申请 | LOS_RwlockRdLock | 申请指定的读模式下的锁 |
| | LOS_RwlockTryRdLock |尝试申请指定的读模式下的锁|
| 写模式下的锁的申请 | LOS_RwlockWrLock | 申请指定的写模式下的锁 |
| | LOS_RwlockTryWrLock |尝试申请指定的写模式下的锁|
| 读写锁的释放 | LOS_RwlockUnLock | 释放指定读写锁 |
| 读写锁有效性判断 | LOS_RwlockIsValid | 判断读写锁有效性 |
**表1** 读写锁模块接口
| 功能分类 | 接口描述 |
| -------- | -------- |
| 读写锁的创建和删除 | -&nbsp;LOS_RwlockInit:创建读写锁<br/>-&nbsp;LOS_RwlockDestroy:删除指定的读写锁 |
| 读模式下的锁的申请 | -&nbsp;LOS_RwlockRdLock:申请指定的读模式下的锁<br/>-&nbsp;LOS_RwlockTryRdLock:尝试申请指定的读模式下的锁 |
| 写模式下的锁的申请 | -&nbsp;LOS_RwlockWrLock:申请指定的写模式下的锁<br/>-&nbsp;LOS_RwlockTryWrLock:尝试申请指定的写模式下的锁 |
| 读写锁的释放 | LOS_RwlockUnLock:释放指定读写锁 |
| 读写锁有效性判断 | LOS_RwlockIsValid:判断读写锁有效性 |
### 开发流程
......
# 信号量
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
- [开发流程](#开发流程)
- [编程实例](#编程实例)
- [实例描述](#实例描述)
- [编程示例](#编程示例)
- [结果验证](#结果验证)
## 基本概念
......@@ -31,8 +22,18 @@
**信号量控制块**
```
/** * 信号量控制块数据结构*/typedefstruct { UINT16 semStat; /*信号量状态 */ UINT16 semType; /*信号量类型 */ UINT16 semCount; /*信号量计数 */ UINT16 semId; /*信号量索引号 */ LOS_DL_LIST semList; /*用于插入阻塞于信号量的任务 */} LosSemCB;
/**
* 信号量控制块数据结构
*/
typedef struct {
UINT16 semStat; /* 信号量状态 */
UINT16 semType; /* 信号量类型 */
UINT16 semCount; /* 信号量计数 */
UINT16 semId; /* 信号量索引号 */
LOS_DL_LIST semList; /* 用于插入阻塞于信号量的任务 */
} LosSemCB;
```
**信号量运作原理**
......@@ -56,8 +57,8 @@
运行示意图如下图所示:
**图1** 小型系统信号量运作示意图
![zh-cn_image_0000001132774752](figures/zh-cn_image_0000001132774752.png)
**图1** 小型系统信号量运作示意图
![zh-cn_image_0000001132774752](figures/zh-cn_image_0000001132774752.png)
## 开发指导
......@@ -65,15 +66,20 @@
### 接口说明
**表1** 信号量模块接口
**表1** 创建/删除信号量
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 创建/删除信号量 | LOS_SemCreate | 创建信号量,返回信号量ID |
| | LOS_BinarySemCreate |创建二值信号量,其计数值最大为1|
| | LOS_SemDelete |删除指定的信号量|
| 申请/释放信号量 | LOS_SemPend | 申请指定的信号量,并设置超时时间 |
| | LOS_SemPost |释放指定的信号量|
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_SemCreate | 创建信号量,返回信号量ID |
| LOS_BinarySemCreate | 创建二值信号量,其计数值最大为1 |
| LOS_SemDelete | 删除指定的信号量 |
**表2** 申请/释放信号量
| 接口**名称** | 描述 |
| -------- | -------- |
| LOS_SemPend | 申请指定的信号量,并设置超时时间 |
| LOS_SemPost | 释放指定的信号量 |
### 开发流程
......@@ -112,6 +118,7 @@
示例代码如下:
```
#include "los_sem.h"
#include "securec.h"
......@@ -230,6 +237,7 @@ UINT32 ExampleSem(VOID)
编译运行得到的结果为:
```
ExampleSemTask2 try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
......
# 用户态快速互斥锁
- [基本概念](#基本概念)
- [运行机制](#运行机制)
## 基本概念
......@@ -18,14 +16,14 @@ Futex(Fast userspace mutex,用户态快速互斥锁)是内核提供的一种
当前哈希桶共有80个,0~63号桶用于存放私有锁(以虚拟地址进行哈希),64~79号桶用于存放共享锁(以物理地址进行哈希),私有/共享属性通过用户态锁的初始化以及Futex系统调用入参确定。
**图1** Futex设计图
![zh-cn_image_0000001127535690](figures/zh-cn_image_0000001127535690.jpg)
**图1** Futex设计图
![zh-cn_image_0000001127535690](figures/zh-cn_image_0000001127535690.jpg)
如图1,每个futex哈希桶中存放被futex_list串联起来的哈希值相同的futex node,每个futex node对应一个被挂起的task,node中key值唯一标识一把用户态锁,具有相同key值的node被queue_list串联起来表示被同一把锁阻塞的task队列。
Futex有以下三种操作:
**表1** Futex模块接口
**表1** Futex模块接口
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
......
# 信号
- [基本概念](#基本概念)
- [运行机制](#运行机制)
## 基本概念
......@@ -12,24 +10,21 @@
信号的运作流程分为三个部分,如表1:
**表1** 信号的运作流程及相关接口(用户态接口)
**表1** 信号的运作流程及相关接口(用户态接口)
| 功能分类 | 接口**名称** | 描述 |
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 注册信号回调函数 | signal | 注册信号总入口及注册和去注册某信号的回调函数。 |
| | sigaction |功能同signal,但增加了信号发送相关的配置选项,目前仅支持SIGINFO结构体中的部分参数。|
| 发送信号 | kill | 发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。 |
| |pthread_kill|发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。|
| |raise|发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。|
| |alarm|发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。|
| |abort|发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。|
| 触发回调 | 无 | 由系统调用与中断触发,内核态与用户态切换前会先进入用户态指定函数并处理完相应回调函数,再回到原用户态程序继续运行。 |
| 注册信号回调函数 | signal: | 注册信号总入口及注册和去注册某信号的回调函数。 |
| 注册信号回调函数 | sigaction | 功能同signal,但增加了信号发送相关的配置选项,目前仅支持SIGINFO结构体中的部分参数。 |
| 发送信号 | kill<br/>pthread_kill<br/>raise<br/>alarm<br/>abort | 发送信号给某个进程或进程内发送消息给某线程,为某进程下的线程设置信号标志位。 |
| 触发回调 | 无 | 由系统调用与中断触发,内核态与用户态切换前会先进入用户态指定函数并处理完相应回调函数,再回到原用户态程序继续运行。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 信号机制为提供给用户态程序进程间通信的能力,故推荐使用上表1列出的用户态POSIX相关接口。
>
> 注册回调函数:
>
>
> ```
> void *signal(int sig, void (*func)(int))(int);
> ```
......@@ -40,6 +35,7 @@
>
> 注册回调函数:
>
>
> ```
> int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict);
> ```
......
# 内核通信机制
- **[事件](kernel-small-basic-trans-event.md)**
- **[信号量](kernel-small-basic-trans-semaphore.md)**
......
# 基础内核
- **[中断及异常处理](kernel-small-basic-interrupt.md)**
- **[进程管理](kernel-small-basic-process.md)**
......
# 适配新的文件系统
- [基本概念](#基本概念)
- [适配Mount接口](#适配mount接口)
- [适配Lookup接口](#适配lookup接口)
- [适配总结和注意事项](#适配总结和注意事项)
## 基本概念
所谓对接VFS层,其实就是指实现VFS层定义的若干接口函数,可根据文件系统的特点和需要适配其中部分接口。一般情况下,支持文件读写,最小的文件系统适配看起来是这样的:
```
struct MountOps g_yourFsMountOps = {
.Mount = YourMountMethod,
......@@ -38,12 +35,14 @@ FSMAP_ENTRY(yourfs_fsmap, "your fs name", g_yourFsMountOps, TRUE, TRUE); // 注
Mount是文件系统第一个被调用的接口,该接口一般会读取驱动的参数,根据配置对文件系统的进行初始化,最后生成文件系统的root节点。Mount接口的定义如下:
```
int (*Mount)(struct Mount *mount, struct Vnode *blkDriver, const void *data);
```
其中,第一个参数struct Mount \*mount是Mount点的信息,适配时需要填写的是下面的变量:
```
struct Mount {
const struct MountOps *ops; /* Mount相关的函数钩子 */
......@@ -56,7 +55,8 @@ struct Mount {
第三个参数const void \*data是mount命令传入的数据,可以根据文件系统的需要处理。
下面以JFFS2为例,详细看一下mount接口是如何适配的:
下面以JFFS2为例,详细看一下mount接口是如何适配的:
```
int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
{
......@@ -137,6 +137,7 @@ const struct MountOps jffs_operations = {
Lookup是查找文件的接口,它的函数原型是:
```
int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);
```
......@@ -145,6 +146,7 @@ int (*Lookup)(struct Vnode *parent, const char *name, int len, struct Vnode **vn
这个接口适配起来思路很清晰,给了父节点的信息和文件名,实现从父目录中查询名字为name的文件这个功能,同样以JFFS2为例:
```
int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **ppVnode)
{
......
# FAT
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [开发流程](#开发流程)
## 基本概念
......@@ -30,6 +26,7 @@ SD卡或MMC的设备名为mmcblk[x]p[y],文件系统类型为“vfat”。
示例:
```
mount("/dev/mmcblk0p0", "/mnt", "vfat", 0, NULL);
```
......
# JFFS2
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
## 基本概念
......@@ -38,11 +35,12 @@ OpenHarmony内核的JFFS2主要应用于NOR FLASH闪存,其特点是:可读
使用mkfs.jffs2工具,制作镜像默认命令如下。页大小默认为4KiB,eraseblock大小默认64KiB。若实际参数与下面不同时,修改相应参数。
```
./mkfs.jffs2 -d rootfs/ -o rootfs.jffs2
```
**表1** 指令含义表(更详细的介绍可以通过mkfs.jffs2 --help来查看)
**表1** 指令含义表(更详细的介绍可以通过mkfs.jffs2 --help来查看)
| 指令 | 含义 |
| -------- | -------- |
......@@ -62,12 +60,14 @@ OpenHarmony内核的JFFS2主要应用于NOR FLASH闪存,其特点是:可读
运行命令:
```
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
```
将从串口得到如下回应信息,表明挂载成功。
```
OHOS # mount /dev/spinorblk1 /jffs1 jffs2
mount OK
......@@ -81,12 +81,14 @@ mount OK
运行命令:
```
OHOS # umount /jffs1
```
将从串口得到如下回应信息,表明卸载成功。
```
OHOS # umount /jffs1
umount ok
......
# NFS
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
## 基本概念
......@@ -24,12 +21,14 @@ OpenHarmony LiteOS-A内核的NFS文件系统指的是NFS的客户端,NFS客户
设置好Ubuntu系统的下载源,保证网络连接好的情况下执行:
```
sudo apt-get install nfs-kernel-server
```
- 创建用于挂载的目录并设置完全权限
```
mkdir -p /home/sqbin/nfs
sudo chmod 777 /home/sqbin/nfs
......@@ -39,6 +38,7 @@ sudo chmod 777 /home/sqbin/nfs
修改NFS配置文件/etc/exports,添加如下一行:
```
/home/sqbin/nfs *(rw,no_root_squash,async)
```
......@@ -47,17 +47,19 @@ sudo chmod 777 /home/sqbin/nfs
执行以下命令启动NFS server:
```
sudo /etc/init.d/nfs-kernel-server start
```
执行以下命令重启NFS server:
```
sudo /etc/init.d/nfs-kernel-server restart
```
1. 设置单板为NFS客户端
2. 设置单板为NFS客户端
本指导中的NFS客户端指运行OpenHarmony内核的设备。
......@@ -71,6 +73,7 @@ OpenHarmony内核设备上的IP信息可通过ifconfig命令查看。
启动以太网或者其他类型网络,使用ping命令检查到服务器的网络是否通畅。
```
OHOS # ping 10.67.212.178
[0]Reply from 10.67.212.178: time=1ms TTL=63
......@@ -83,6 +86,7 @@ OHOS # ping 10.67.212.178
客户端NFS初始化,运行命令:
```
OHOS # mkdir /nfs
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
......@@ -90,6 +94,7 @@ OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
将从串口得到如下回应信息,表明初始化NFS客户端成功。
```
OHOS # mount 10.67.212.178:/home/sqbin/nfs /nfs nfs 1011 1000
Mount nfs on 10.67.212.178:/home/sqbin/nfs, uid:1011, gid:1000
......@@ -103,6 +108,7 @@ Mount nfs finished.
>
> mount命令的格式为:
>
>
> ```
> mount <SERVER_IP:SERVER_PATH> <CLIENT_PATH> nfs
> ```
......@@ -111,22 +117,25 @@ Mount nfs finished.
>
> 如果不想有NFS访问权限限制,可以在Linux命令行将NFS根目录权限设置成777:
>
>
> ```
> chmod -R 777 /home/sqbin/nfs
> ```
>
> 至此,NFS客户端设置完毕。NFS文件系统已成功挂载。
1. 利用NFS共享文件
3. 利用NFS共享文件
在NFS服务器下新建目录dir,并保存。在OpenHarmony内核下运行ls命令:
```
OHOS # ls /nfs
```
则可从串口得到如下回应:
```
OHOS # ls /nfs
Directory /nfs:
......
# Procfs
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [编程实例](#编程实例)
## 基本概念
......@@ -30,6 +26,7 @@ procfs文件的创建无法使用一般的文件系统接口,需要使用ProcM
3.当写文件内容时,打印写入的内容
```
#include "proc_fs.h"
......@@ -78,6 +75,7 @@ void HelloWorldInit(void)
启动后在shell输入如下命令
```
OHOS # cat /proc/hello/world
OHOS # Hello World!
......
# Ramfs
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
## 基本概念
......@@ -18,24 +15,28 @@ RAMFS文件系统把所有的文件都放在 RAM 中,所以读/写操作发生
挂载:
```
mount(NULL, "/dev/shm", "ramfs", 0, NULL)
```
创建目录:
```
mkdir(pathname, mode)
```
创建文件:
```
open(pathname, O_NONBLOCK | O_CREAT | O_RDWR, mode)
```
读取目录:
```
dir = opendir(pathname)
ptr = readdir(dir)
......@@ -44,18 +45,21 @@ closedir(dir)
删除文件:
```
unlink(pathname)
```
删除目录:
```
rmdir(pathname)
```
去挂载:
```
umount("/dev/shm")
```
......
# 支持的文件系统
- **[FAT](kernel-small-bundles-fs-support-fat.md)**
- **[JFFS2](kernel-small-bundles-fs-support-jffs2.md)**
......
# 文件系统
文件系统(File System,或者简称FS),是操作系统中输入输出的一种主要形式,主要负责和内外部的存储设备交互。
文件系统对上通过C库提供的POSIX标准的操作接口,具体可以参考C库的API文档说明。对下,通过内核态的VFS虚拟层,屏蔽了各个具体文件系统的差异。基本架构如下:
**图1** 文件系统的总体结构
![zh-cn_image_0000001125101908](figures/zh-cn_image_0000001125101908.png)
**图1** 文件系统的总体结构
![zh-cn_image_0000001125101908](figures/zh-cn_image_0000001125101908.png)
- **[虚拟文件系统](kernel-small-bundles-fs-virtual.md)**
- **[支持的文件系统](kernel-small-bundles-fs-support.md)**
- **[适配新的文件系统](kernel-small-bundles-fs-new.md)**
- **[适配新的文件系统](kernel-small-bundles-fs-new.md)**
\ No newline at end of file
# 轻量级进程间通信
- [基本概念](#基本概念)
- [运行机制](#运行机制)
- [开发指导](#开发指导)
- [接口说明](#接口说明)
## 基本概念
......@@ -22,15 +18,13 @@ LiteIPC中有两个主要概念,一个是ServiceManager,另一个是Service
### 接口说明
**表1** LiteIPC模块接口(仅LiteOS-A内部使用)
**表1** LiteIPC模块接口(仅LiteOS-A内部使用)
| 功能分类 | 接口**名称** | 描述 |
| -------- | -------- | -------- |
| 模块初始化 | OsLiteIpcInit | 初始化LiteIPC模块 |
| IPC消息内存池 | LiteIpcPoolInit | 初始化进程的IPC消息内存池 |
| | LiteIpcPoolReInit |重新初始化进程的IPC消息内存池|
| | LiteIpcPoolDelete |释放进程的IPC消息内存池|
| Service管理 | LiteIpcRemoveServiceHandle | 删除指定的Service |
| 功能分类 | 接口描述 |
| -------- | -------- |
| 模块初始化 | OsLiteIpcInit:初始化LiteIPC模块 |
| IPC消息内存池 | -&nbsp;LiteIpcPoolInit:初始化进程的IPC消息内存池<br/>-&nbsp;LiteIpcPoolReInit:重新初始化进程的IPC消息内存池<br/>-&nbsp;LiteIpcPoolDelete:释放进程的IPC消息内存池 |
| Service管理 | LiteIpcRemoveServiceHandle:删除指定的Service |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> LiteIPC模块接口都只在LiteOS-A内部使用。
# 扩展组件
- **[系统调用](kernel-small-bundles-system.md)**
- **[动态加载与链接](kernel-small-bundles-linking.md)**
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册