未验证 提交 11109b1b 编写于 作者: O openharmony_ci 提交者: Gitee

!12967 liteos_m文档优化

Merge pull request !12967 from wangchen/1227_doc
......@@ -26,6 +26,7 @@
- [异常调测](kernel-mini-memory-exception.md)
- [Trace调测](kernel-mini-memory-trace.md)
- [LMS调测](kernel-mini-memory-lms.md)
- [SHELL](kernel-mini-debug-shell.md)
- 附录
- [内核编码规范](kernel-mini-appx-code.md)
- [标准库支持](kernel-mini-appx-lib.md)
......
......@@ -459,6 +459,8 @@ demo功能:
创建一个线程并将父线程中的信息传递给子线程,在子线程中打印传递过来的信息和自身线程id值。
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数DemoForTest。
```
#include <stdio.h>
......
# SHELL
OpenHarmony内核提供的Shell支持调试常用的基本功能,包含系统、文件、网络相关命令。同时OpenHarmony内核的Shell支持添加新的命令,可以根据需求来进行定制。
Shell功能仅供调试使用,暂不支持tab按键补全,按键回退等功能。
部分命令需要通过make menuconfig开启对应选项才可使用。
## 常用命令介绍
### cat
用于显示文本文件的内容。需开启LOSCFG_FS_VFS。
###### 命令格式
cat [FILE]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---- | ---------- | -------------- |
| FILE | 文件路径。 | 已存在的文件。 |
### cd
用来改变当前目录。需开启LOSCFG_FS_VFS。
###### 命令格式
cd [path]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---- | ---------- | -------------- |
| path | 文件路径。 | 已存在的路径。 |
### cp
拷贝文件,创建一份副本。需开启LOSCFG_FS_VFS。
###### 命令格式
cp [SOURCEFILE] [DESTFILE]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---------- | ---------------------- | ----------------------------------------- |
| SOURCEFILE | 源文件路径。文件路径。 | 目前只支持文件,不支持目录;文件不可为空。 |
| DESTFILE | 目的文件路径。 | 支持目录以及文件名;目录需有效。 |
### date
用于查询系统日期和时间。
###### 命令格式
date
###### 参数说明
### free
显示系统内存的使用情况。
###### 命令格式
free [ -k | -m ]
###### 参数说明
| 参数 | 参数说明 | 取值范围 |
| ---- | ----------------- | -------- |
| -k | 以KiB为单位显示。 | N/A |
| -m | 以MiB为单位显示。 | N/A |
### help
显示当前操作系统内所有操作指令。
###### 命令格式
help
###### 参数说明
### ifconfig
用来查询网卡的IP地址、网络掩码、网关、硬件mac地址等参数。需开启LWIP_SHELLCMD_ENABLE。
###### 命令格式
ifconfig
###### 参数说明
### ls
用来显示当前目录的内容。需开启LOSCFG_FS_VFS。
###### 命令格式
###### ls [DIRECTORY]
| 参数 | 参数说明 | 取值范围 |
| --------- | ---------- | ------------------------------------------------------------ |
| DIRECTORY | 文件路径。 | DIRECTORY为空时,显示当前目录的内容。<br/>DIRECTORY为有效目录路径时,会显示对应目录下的内容。<br/>当前LiteOS-M不支持根目录 "/"。 |
### memusage
用来显示内存使用水线。
###### 命令格式
###### memusage [-k/-m]
| 参数 | 参数说明 | 取值范围 |
| ---- | ----------------- | -------- |
| -k | 以KiB为单位显示。 | N/A |
| -m | 以MiB为单位显示。 | N/A |
### mkdir
用来创建一个目录。需开启LOSCFG_FS_VFS。
###### 命令格式
###### mkdir [DIRECTORY]
| 参数 | 参数说明 | 取值范围 |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | 文件路径。 | DIRECTORY可以传入绝对路径和相对路径。 |
### ping
用来测试网络连接是否正常。需开启LWIP_SHELLCMD_ENABLE。
###### 命令格式
###### ping [ip]
| 参数 | 参数说明 | 取值范围 |
| ---- | ------------------------------ | -------- |
| ip | 要测试是否网络连通的IPv4地址。 | N/A |
### pwd
用来显示当前路径。需开启LOSCFG_FS_VFS。
###### 命令格式
###### pwd
### rm
用来删除文件或文件夹。需开启LOSCFG_FS_VFS。
###### 命令格式
###### rm [FILE] or rm [-r/-R] [FILE]
| 参数 | 参数说明 | 取值范围 |
| ----- | ------------------------------- | -------------------------------- |
| FILE | 文件名,可以是文件或者文件夹 。 | FILE可以传入绝对路径和相对路径。 |
| -r/-R | FILE是文件夹时需要有-r /-R。 | N/A |
### rmdir
用来删除文件夹。需开启LOSCFG_FS_VFS。
###### 命令格式
###### rmdir [DIRECTORY]
| 参数 | 参数说明 | 取值范围 |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | 文件路径。 | DIRECTORY可以传入绝对路径和相对路径。 |
### task
用来显示当前各任务状态。
###### 命令格式
###### task
显示内容主要包括任务号,优先级,状态,栈信息,信号,事件,CPU占用率,任务名称等
### touch
用来创建文件。需开启LOSCFG_FS_VFS。
###### 命令格式
###### touch [FILE]
| 参数 | 参数说明 | 取值范围 |
| ---- | -------- | -------------------------------- |
| FILE | 文件名。 | FILE可以传入绝对路径和相对路径。 |
### stack
用来查看指定任务的栈内容。需开启编译选项 LOSCFG_DEBUG_TOOLS,功能开启会影响性能。
###### 命令格式
###### stack [ID]
| 参数 | 参数说明 | 取值范围 |
| ---- | -------- | ------------------------ |
| ID | 任务ID。 | 任务ID对应的任务需存在。 |
### hwi
用来查看中断的占用率。需开启编译选项 LOSCFG_DEBUG_TOOLS,功能开启会影响性能。
###### 命令格式
###### hwi
### st
用来查看调度信息。需开启编译选项 LOSCFG_DEBUG_TOOLS,功能开启会影响性能。
###### 命令格式
###### st -s | st -e
| 参数 | 参数说明 | 取值范围 |
| ---- | ---------------------- | -------- |
| -s | 开始记录调度信息 | N/A |
| -e | 停止记录并打印调度信息 | N/A |
......@@ -5,14 +5,18 @@
CPU(中央处理器,Central Processing Unit)占用率分为系统CPU占用率和任务CPU占用率。
系统CPU占用率(CPU Percent)是指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示系统满负荷运转。
**系统CPU占用率**:是指周期时间内系统的CPU占用率,用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。系统CPU占用率的有效表示范围为0~100,其单位为百分比。100表示系统满负荷运转。
任务CPU占用率指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其精度(可通过配置调整)为百分比。100表示在一段时间内系统一直在运行该任务。
**任务CPU占用率**:指单个任务的CPU占用率,用于表示单个任务在一段时间内的闲忙程度。任务CPU占用率的有效表示范围为0~100,其单位为百分比。100表示在一段时间内系统一直在运行该任务。
用户通过系统级的CPU占用率,判断当前系统负载是否超出设计规格。
通过系统中各个任务的CPU占用情况,判断各个任务的CPU占用率是否符合设计的预期。
此外开启CPUP的情况下,可选择开启中断占用率统计。
**中断占用率**:是指单个中断在全部中断消耗时间的占用率。占用率的有效表示范围为0~100。100表示在一段时间内仅触发该中断。
## 运行机制
......@@ -23,15 +27,18 @@ OpenHarmony LiteOS-M的CPUP(CPU Percent,系统CPU占用率)采用任务
OpenHarmony LiteOS-M提供以下两种CPU占用率的信息查询:
- 系统CPU占用率。
- 任务CPU占用率。
**CPU占用率的计算方法:**
此外,系统还提供了中断占用率的信息查询能力(需同时开启CPUP和定时器)。
**占用率的计算方法:**
系统CPU占用率=系统中除idle任务外其他任务运行总时间/系统运行总时间
任务CPU占用率=任务运行总时间/系统运行总时间
中断占用率=单个中断运行时间/中断运行总时间
## 接口说明
......@@ -39,28 +46,29 @@ OpenHarmony LiteOS-M提供以下两种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占用率 |
| 获取系统CPU占用率 | &nbsp;LOS_SysCpuUsage:获取当前系统CPU占用率<br/>&nbsp;LOS_HistorySysCpuUsage:获取系统历史CPU占用率 |
| 获取任务CPU占用率 | &nbsp;LOS_TaskCpuUsage:获取指定任务CPU占用率<br/>&nbsp;LOS_HistoryTaskCpuUsage:获取指定任务历史CPU占用率<br/>&nbsp;LOS_AllTaskCpuUsage:获取所有任务CPU占用率 |
| 输出任务CPU占用率 | LOS_CpupUsageMonitor:输出任务历史CPU占用率 |
| 获取中断CPU占用率 | LOS_GetAllIrqCpuUsage:获取所有中断CPU占用率 |
## 开发流程
CPU占用率的典型开发流程:
1. 调用获取系统CPU使用率函数LOS_SysCpuUsage。
1. 调用获取系统CPU用率函数LOS_SysCpuUsage。
2. 调用获取系统历史CPU使用率函数LOS_HistorySysCpuUsage。
2. 调用获取系统历史CPU用率函数LOS_HistorySysCpuUsage。
3. 调用获取指定任务CPU使用率函数LOS_TaskCpuUsage。
3. 调用获取指定任务CPU使用率函数LOS_TaskCpuUsage。
- 若任务已创建,则关中断,正常获取,恢复中断;
- 若任务未创建,则返回错误码;
4. 调用获取指定任务历史CPU使用率函数LOS_HistoryTaskCpuUsage。
4. 调用获取指定任务历史CPU用率函数LOS_HistoryTaskCpuUsage。
- 若任务已创建,则关中断,根据不同模式正常获取,恢复中断;
- 若任务未创建,则返回错误码;
5. 调用获取所有任务CPU使用率函数LOS_AllCpuUsage。
5. 调用获取所有任务CPU用率函数LOS_AllCpuUsage。
- 若CPUP已初始化,则关中断,根据不同模式正常获取,恢复中断;
- 若CPUP未初始化或有非法入参,则返回错误码;
......@@ -91,53 +99,62 @@ CPU占用率的典型开发流程:
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleCpup。
```
#include "los_task.h"
#include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
#define TEST_TASK_PRIO 5
#define TASK_DELAY_TIME 100
VOID CpupTask(VOID)
{
printf("entry cpup test example\n");
while(1) {
usleep(100);
}
usleep(TASK_DELAY_TIME);
usleep(TASK_DELAY_TIME);
printf("exit cpup test example\n");
}
UINT32 ItCpupTest(VOID)
UINT32 ExampleCpup(VOID)
{
UINT32 ret;
UINT32 cpupUse;
TSK_INIT_PARAM_S cpupTestTask = { 0 };
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S));
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
UINT32 taskID;
TSK_INIT_PARAM_S cpupTestTask = { 0 };
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)CpupTask;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800;
cpupTestTask.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
cpupTestTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
cpupTestTask.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &cpupTestTask);
if(ret != LOS_OK) {
printf("cpupTestTask create failed .\n");
return LOS_NOK;
}
usleep(100);
usleep(TASK_DELAY_TIME);
/* 获取当前系统CPU占用率 */
cpupUse = LOS_SysCpuUsage();
printf("the current system cpu usage is: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
/* 获取指定任务的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */
/* 获取当前系统历史CPU占用率 */
cpupUse = LOS_HistorySysCpuUsage(CPUP_LESS_THAN_1S);
printf("the history system cpu usage in all time:%u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_TaskCpuUsage(g_cpuTestTaskID);
/* 获取指定历史任务在系统启动到现在的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */
/* 获取指定任务的CPU占用率 */
cpupUse = LOS_TaskCpuUsage(taskID);
printf("cpu usage of the cpupTestTask:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* 获取指定任务在系统启动到现在的CPU占用率 */
cpupUse = LOS_HistoryTaskCpuUsage(taskID, CPUP_LESS_THAN_1S);
printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
}
```
......@@ -149,8 +166,16 @@ UINT32 ItCpupTest(VOID)
```
entry cpup test example
the current system cpu usage is : 1.5
the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask: TaskID:10 usage: 0.0
cpu usage of the cpupTestTask&nbsp;in all time: TaskID:10 usage: 0.0
the current system cpu usage is: 8.2
the history system cpu usage in all time:8.9
cpu usage of the cpupTestTask:
TaskID: 5
usage: 0.5
cpu usage of the cpupTestTask in all time:
TaskID: 5
usage: 0.5
exit cpup test example
根据实际运行环境,上文中的数据会有差异,非固定结果
```
# 文件系统
## VFS
M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同A核一样,通过VFS层提供了POSIX标准的操作,保持了接口的一致性,但是因为M核的资源非常紧张,VFS层非常轻薄,没有提供类似A核的高级功能(如pagecache等),主要是接口的标准化和适配工作,具体的事务由各个文件系统实际承载。M核文件系统支持的功能如下表所示:
### 基本概念
**VFS(Virtual File System)** 是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。
M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。通过VFS层提供了POSIX标准的操作,保持了接口的一致性,但是因为M核的资源非常紧张,VFS层非常轻薄,没有提供类似A核的高级功能(如pagecache等),主要是接口的标准化和适配工作,具体的事务由各个文件系统实际承载。M核文件系统支持的功能如下表所示:
### 接口说明
**表1** 文件操作
**表1** 文件操作
| 接口名 | 描述 | FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- |
......@@ -13,10 +20,10 @@ M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同
| read | 读取文件内容 | 支持 | 支持 |
| write | 往文件写入内容 | 支持 | 支持 |
| lseek | 设置文件偏移位置 | 支持 | 支持 |
| stat | 通过文件路径名获取文件信息 | 支持 | 支持 |
| unlink | 删除文件 | 支持 | 支持 |
| rename | 重命名文件 | 支持 | 支持 |
| fstat | 通过文件句柄获取文件信息 | 支持 | 支持 |
| stat | 通过文件路径名获取文件信息 | 支持 | 支持 |
| fsync | 文件内容刷入存储设备 | 支持 | 支持 |
......@@ -40,6 +47,8 @@ M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS。同
| umount2 | 分区卸载,可通过MNT_FORCE参数进行强制卸载 | 支持 | 不支持 |
| statfs | 获取分区信息 | 支持 | 不支持 |
ioctl,fcntl等接口由不同的lib库支持,与底层文件系统无关。
## FAT
......@@ -68,7 +77,86 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
#define FAT_MAX_OPEN_FILES 50
```
#### 分区挂载
移植FATFS到新硬件设备上,需要在初始化flash驱动后,完成设备分区。
设备分区接口:int LOS_DiskPartition(const char *dev, const char *fsType, int *lengthArray, int *addrArray, int partNum);
- dev:设备名称, 如“spinorblk0”
- fsType:文件系统类型,”vfat“
- lengthArray:该设备上各分区的长度列表,fatfs填入百分比即可
- addrArray:该设备上各分区的起始地址列表
- partNum:分区的个数
格式化接口:int LOS_PartitionFormat(const char *partName, char *fsType, void *data);
- partName:分区名称,设备名称+ ‘p’ + 分区号,如“spinorblk0p0”
- fsType:文件系统类型,”vfat“
- data:私有数据 传入(VOID *)formatType,(如FMT_FAT, FMT_FAT32)
mount接口:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
- source:分区名称,设备名称+ ‘p’ + 分区号,如“spinorblk0p0”
- target:挂载路径
- filesystemtype:文件系统类型,”vfat“
- mountflags:mount配置参数
- data:私有数据,传入(VOID *)formatType,(如FMT_FAT, FMT_FAT32)
本参考代码已在 ./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c 中实现,M核qemu上可直接使用,请参考并根据实际硬件修改。
#include "fatfs_conf.h"
#include "fs_config.h"
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 FatfsLowLevelInit()
{
INT32 ret;
INT32 i;
UINT32 addr;
int data = FMT_FAT32;
const char * const pathName[FF_VOLUMES] = {FF_VOLUME_STRS};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* 获取长度和起始地址的函数,请根据实际单板适配 */
INT32 lengthArray[FF_VOLUMES] = {25, 25, 25, 25};
INT32 addrArray[FF_VOLUMES];
/* 配置各分区的地址和长度,请根据实际单板适配 */
for (i = 0; i < FF_VOLUMES; i++) {
addr = halPartitionsInfo[FLASH_PARTITION_DATA1].partitionStartAddr + i * 0x10000;
addrArray[i] = addr;
FlashInfoInit(i, addr);
}
/* 配置分区信息,请根据实际单板适配 */
SetupDefaultVolToPartTable();
ret = LOS_DiskPartition("spinorblk0", "vfat", lengthArray, addrArray, FF_VOLUMES);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = LOS_PartitionFormat("spinorblk0p0", "vfat", &data);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount("spinorblk0p0", "/system", "vfat", 0, &data);
printf("%s: mount fs on '%s' %s\n", __func__, pathName[0], (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
#### 开发流程
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
......@@ -100,9 +188,9 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
本实例实现以下功能:
1. 创建目录“user/test”
1. 创建目录“system/test”
2. 在“user/test”目录下创建文件“file.txt”
2. 在“system/test”目录下创建文件“file.txt”
3. 在文件起始位置写入“Hello OpenHarmony!”
......@@ -123,97 +211,98 @@ FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC
**前提条件:**
系统已将MMC设备分区挂载到user目录
系统已将设备分区挂载到目录,qemu默认已挂载system。
**代码实现如下:**
```
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleFatfs。
#define LOS_OK 0
#define LOS_NOK -1
int FatfsTest(void)
{
```
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "system" /* 测试的根目录请根据实际情况调整 */
VOID ExampleFatfs(VOID)
{
int ret;
int fd = -1;
int fd;
ssize_t len;
off_t off;
char dirName[20] = "user/test";
char fileName[20] = "user/test/file.txt";
char writeBuf[20] = "Hello OpenHarmony!";
char readBuf[20] = {0};
char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[BUF_SIZE] = {0};
/* 创建目录“user/test” */
/* 创建测试目录 */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return LOS_NOK;
return;
}
/* 创建可读写文件"user/test/file.txt" */
/* 创建可读写测试文件 */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return LOS_NOK;
return;
}
/* 将writeBuf中的内容写入文件 */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return LOS_NOK;
return;
}
/* 将文件内容刷入存储设备中 */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return LOS_NOK;
return;
}
/* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return LOS_NOK;
return;
}
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return LOS_NOK;
return;
}
printf("%s\n", readBuf);
/* 关闭文件 */
/* 关闭测试文件 */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return LOS_NOK;
return;
}
/* 删除文件"user/test/file.txt" */
/* 删除测试文件 */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return LOS_NOK;
return;
}
/* 删除目录“user/test” */
/* 删除测试目录 */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return LOS_NOK;
return;
}
return LOS_OK;
}
return;
}
```
......@@ -237,86 +326,194 @@ LittleFS是一个小型的Flash文件系统,它结合日志结构(log-struct
### 开发指导
移植LittleFS到新硬件设备上,需要申明lfs_config:
移植LittleFS到新硬件设备上,需要在初始化flash驱动后,完成设备分区。
设备分区接口:int LOS_DiskPartition(const char *dev, const char *fsType, int *lengthArray, int *addrArray, int partNum);
- dev:设备名称
- fsType:文件系统类型, "littlefs"
- lengthArray:该设备上各分区的长度列表
- addrArray:该设备上各分区的起始地址列表
- partNum:分区的个数
格式化接口:int LOS_PartitionFormat(const char *partName, char *fsType, void *data);
- partName:分区名称
- fsType:文件系统类型, "littlefs"
- data:私有数据 传入(VOID *)struct fs_cfg
mount接口:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
- source:分区名称
- target:挂载路径
- filesystemtype:文件系统类型,"littlefs"
- mountflags:mount配置参数
- data:私有数据,传入(VOID *)struct fs_cfg
本参考代码已在 ./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c 中实现,M核qemu上可直接使用,请参考并根据实际硬件修改。
```
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
.erase = user_provided_block_device_erase,
.sync = user_provided_block_device_sync,
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 LfsLowLevelInit()
{
INT32 ret;
struct fs_cfg fs[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* 获取长度和起始地址的函数,请根据实际单板适配 */
INT32 lengthArray[2];
lengthArray[0]= halPartitionsInfo[FLASH_PARTITION_DATA0].partitionLength;
INT32 addrArray[2];
addrArray[0] = halPartitionsInfo[FLASH_PARTITION_DATA0].partitionStartAddr;
ret = LOS_DiskPartition("flash0", "littlefs", lengthArray, addrArray, 2);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
fs[0].mount_point = "/littlefs";
fs[0].partCfg.partNo = 0;
fs[0].partCfg.blockSize = 4096; /* 4096, lfs block size */
fs[0].partCfg.blockCount = 1024; /* 2048, lfs block count */
fs[0].partCfg.readFunc = virt_flash_read; /* flash读函数,请根据实际单板适配 */
fs[0].partCfg.writeFunc = virt_flash_write; /* flash写函数,请根据实际单板适配 */
fs[0].partCfg.eraseFunc = virt_flash_erase; /* flash擦函数,请根据实际单板适配 */
fs[0].partCfg.readSize = 256; /* 256, lfs read size */
fs[0].partCfg.writeSize = 256; /* 256, lfs prog size */
fs[0].partCfg.cacheSize = 256; /* 256, lfs cache size */
fs[0].partCfg.lookaheadSize = 16; /* 16, lfs lookahead size */
fs[0].partCfg.blockCycles = 1000; /* 1000, lfs block cycles */
ret = LOS_PartitionFormat("flash0", "littlefs", &fs[0].partCfg);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount(NULL, fs[0].mount_point, "littlefs", 0, &fs[0].partCfg);
printf("%s: mount fs on '%s' %s\n", __func__, fs[0].mount_point, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
```
其中.read,.prog,.erase,.sync分别对应该硬件平台上的底层的读写\擦\同等接口。
其中.readFunc,.writeFunc,.eraseFunc分别对应该硬件平台上的底层的读写\擦等接口。
read_size 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。
readSize 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。
prog_size 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是read_size的整数倍,但值太大会带来更多的内存消耗。
writeSize 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是readSize的整数倍,但值太大会带来更多的内存消耗。
block_size 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是prog_size的整数倍。
blockSize 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是writeSize的整数倍。
block_count 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
blockCount 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
### 示例代码
代码实现如下:
**前提条件:**
系统已将设备分区挂载到目录,qemu默认已挂载/littlefs。
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleLittlefs。
```
#include "lfs.h"
#include "stdio.h"
lfs_t lfs;
lfs_file_t file;
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
.erase = user_provided_block_device_erase,
.sync = user_provided_block_device_sync,
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
};
int main(void) {
// mount the filesystem
int err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "/littlefs" /* 测试的根目录请根据实际情况调整 */
VOID ExampleLittlefs(VOID)
{
int ret;
int fd;
ssize_t len;
off_t off;
char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[BUF_SIZE] = {0};
/* 创建测试目录 */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return;
}
/* 创建可读写测试文件 */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return;
}
/* 将writeBuf中的内容写入文件 */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return;
}
/* 将文件内容刷入存储设备中 */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return;
}
// read current count
uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// update boot count
boot_count += 1;
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully
lfs_file_close(&lfs, &file);
// release any resources we were using
lfs_unmount(&lfs);
// print the boot count
printf("boot_count: %d\n", boot_count);
/* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return;
}
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return;
}
printf("%s\n", readBuf);
/* 关闭测试文件 */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return;
}
/* 删除测试文件 */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return;
}
/* 删除测试目录 */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return;
}
return LOS_OK;
}
```
......@@ -327,5 +524,5 @@ int main(void) {
```
Say hello 1 times.
Hello OpenHarmony!
```
\ No newline at end of file
......@@ -62,7 +62,9 @@ typedef struct {
#### 示例代码
代码实现如下:
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemTest。
```
#include <stdio.h>
......@@ -71,7 +73,7 @@ typedef struct {
#include "los_memory.h"
#include "los_config.h"
#define TEST_TASK_PRIO 5
void MemInfoTaskFunc(void)
{
LOS_MEM_POOL_STATUS poolStatus = {0};
......@@ -80,11 +82,11 @@ void MemInfoTaskFunc(void)
void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus);
/* 算出内存池当前的碎片率百分比 */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
float fragment = 100 - poolStatus.maxFreeNodeSize * 100.0 / poolStatus.totalFreeSize;
/* 算出内存池当前的使用率百分比 */
unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool);
printf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize,
poolStatus.totalFreeSize, poolStatus.usageWaterLine);
float usage = LOS_MemTotalUsedGet(pool) * 100.0 / LOS_MemPoolSizeGet(pool);
printf("usage = %f, fragment = %f, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment,
poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
}
int MemTest(void)
......@@ -93,9 +95,9 @@ int MemTest(void)
unsigned int taskID;
TSK_INIT_PARAM_S taskStatus = {0};
taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc;
taskStatus.uwStackSize = 0x1000;
taskStatus.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
taskStatus.pcName = "memInfo";
taskStatus.usTaskPrio = 10;
taskStatus.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
......@@ -112,7 +114,9 @@ int MemTest(void)
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
usage = 0.458344, fragment = 0.000000, maxFreeSize = 16474928, totalFreeSize = 16474928, waterLine = 76816
根据实际运行环境,上文中的数据会有差异,非固定结果
```
## 内存泄漏检测
......@@ -179,6 +183,10 @@ node size LR[0] LR[1] LR[2]
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemLeakTest。
qemu中进行验证时,由于代码段位置特殊需调整ld文件_stext位置到text段的起始位置
```
#include <stdio.h>
......@@ -198,7 +206,7 @@ void MemLeakTest(void)
#### 结果验证
编译运行输出log如下:
编译运行输出示例log如下:
```
......@@ -217,6 +225,8 @@ node size LR[0] LR[1] LR[2]
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
根据实际运行环境,上文中的数据会有差异,非固定结果
```
对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块:
......@@ -225,6 +235,8 @@ node size LR[0] LR[1] LR[2]
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
根据实际运行环境,上文中的数据会有差异,非固定结果
```
部分汇编文件如下:
......@@ -246,6 +258,8 @@ node size LR[0] LR[1] LR[2]
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0
根据实际运行环境,上文中的数据会有差异,非固定结果
```
其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。
......@@ -295,6 +309,8 @@ LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemIntegrityTest。
```
#include <stdio.h>
......@@ -320,20 +336,28 @@ void MemIntegrityTest(void)
```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
/* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
broken node head LR info: /* 节点的LR信息需要开启内存检测功能才有有效输出 */
LR[0]:0x0800414e
LR[1]:0x08000cc2
LR[2]:0x00000000
pre node head LR info: /* 通过LR信息,可以在汇编文件中查找前节点是哪里申请,然后排查其使用的准确性 */
LR[0]:0x08004144
LR[1]:0x08000cc2
LR[2]:0x00000000
[ERR]Memory interity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* 被破坏节点和其前节点的地址 */
/* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error!
memory used but magic num wrong, magic num = 0x0
/* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
broken node head: 0x2103d7e8 0x0 0x80000020, prev node head: 0x2103c7cc 0xabcddcba 0x80000020
/* 节点的LR信息需要开启内存检测功能才有有效输出 */
broken node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* 通过LR信息,可以在汇编文件中查找前节点是哪里申请,然后排查其使用的准确性 */
pre node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* 被破坏节点和其前节点的地址 */
[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0
根据实际运行环境,上文中的数据会有差异,非固定结果
```
......@@ -49,6 +49,8 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
1. 使用示例中有问题的代码,编译、运行工程,在串口终端中查看异常信息输出。示例代码模拟异常代码,实际产品开发时使用异常调测机制定位异常问题。
本示例演示异常输出,包含1个任务,该任务入口函数模拟若干函数调用,最终调用一个模拟异常的函数。代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleExcEntry。
```
#include <stdio.h>
#include "los_config.h"
......@@ -59,29 +61,30 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
#define TSK_PRIOR 4
/* 模拟异常函数 */
UINT32 Get_Result_Exception_0(UINT16 dividend){
UINT32 divisor = 0;
UINT32 result = dividend / divisor;
UINT32 GetResultException0(UINT16 dividend){
UINT32 result = *(UINT32 *)(0xffffffff);
printf("Enter GetResultException0. %u\r\n", result);
return result;
}
UINT32 Get_Result_Exception_1(UINT16 dividend){
return Get_Result_Exception_0(dividend);
UINT32 GetResultException1(UINT16 dividend){
printf("Enter GetResultException1.\r\n");
return GetResultException0(dividend);
}
UINT32 Get_Result_Exception_2(UINT16 dividend){
return Get_Result_Exception_1(dividend);
UINT32 GetResultException2(UINT16 dividend){
printf("Enter GetResultException2.\r\n");
return GetResultException1(dividend);
}
UINT32 Example_Exc(VOID)
UINT32 ExampleExc(VOID)
{
UINT32 ret;
printf("Enter Example_Exc Handler.\r\n");
/* 模拟函数调用 */
ret = Get_Result_Exception_2(TSK_PRIOR);
ret = GetResultException2(TSK_PRIOR);
printf("Divided result =%u.\r\n", ret);
printf("Exit Example_Exc Handler.\r\n");
......@@ -90,20 +93,20 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
/* 任务测试入口函数,创建一个会发生异常的任务 */
UINT32 Example_Exc_Entry(VOID)
UINT32 ExampleExcEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam;
TSK_INIT_PARAM_S initParam = { 0 };
/* 锁任务调度,防止新创建的任务比本任务高而发生调度 */
LOS_TaskLock();
printf("LOS_TaskLock() Success!\r\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Exc;
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleExc;
initParam.usTaskPrio = TSK_PRIOR;
initParam.pcName = "Example_Exc";
initParam.uwStackSize = LOSCFG_SECURE_STACK_DEFAULT_SIZE;
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
/* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
ret = LOS_TaskCreate(&g_taskExcId, &initParam);
if (ret != LOS_OK) {
......@@ -122,73 +125,63 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
}
```
1.述代码串口终端输出异常信息如下:
述代码串口终端输出异常信息如下:
```
entering kernel init...
LOS_TaskLock() Success!
Example_Exc create Success!
Entering scheduler
Enter Example_Exc Handler.
*Exception Information**
Type = 10
ThrdPid = 4
Enter GetResultException2.
Enter GetResultException1.
*************Exception Information**************
Type = 4
ThrdPid = 5
Phase = exc in task
FaultAddr = 0xabababab
FaultAddr = 0xfffffffc
Current task info:
Task name = Example_Exc
Task ID = 4
Task SP = 0x200051ac
Task ST = 0x20004ff0
Task SS = 0x200
Task ID = 5
Task SP = 0x210549bc
Task ST = 0x21053a00
Task SS = 0x1000
Exception reg dump:
PC = 0x80037da
LR = 0x80037fe
SP = 0x20005190
PC = 0x2101c61a
LR = 0x2101c64d
SP = 0x210549a8
R0 = 0x4
R1 = 0x40
R2 = 0x4
R3 = 0x0
R4 = 0x4040404
R1 = 0xa
R2 = 0x0
R3 = 0xffffffff
R4 = 0x2103fb20
R5 = 0x5050505
R6 = 0x6060606
R7 = 0x20005190
R7 = 0x210549a8
R8 = 0x8080808
R9 = 0x9090909
R10 = 0x10101010
R11 = 0x11111111
R12 = 0x12121212
R12 = 0x0
PriMask = 0x0
xPSR = 0x41000000
----- backtrace start -----
backtrace 0 -- lr = 0x800381a
backtrace 1 -- lr = 0x8003836
backtrace 2 -- lr = 0x8005a4e
backtrace 3 -- lr = 0x8000494
backtrace 4 -- lr = 0x8008620
backtrace 5 -- lr = 0x800282c
backtrace 6 -- lr = 0x80008a0
backtrace 7 -- lr = 0x80099f8
backtrace 8 -- lr = 0x800a01a
backtrace 9 -- lr = 0x800282c
backtrace 10 -- lr = 0x80008a0
backtrace 11 -- lr = 0x80099f8
backtrace 12 -- lr = 0x8009bf0
backtrace 13 -- lr = 0x8009c52
backtrace 14 -- lr = 0x80099aa
backtrace 0 -- lr = 0x2101c64c
backtrace 1 -- lr = 0x2101c674
backtrace 2 -- lr = 0x2101c696
backtrace 3 -- lr = 0x2101b1ec
----- backtrace end -----
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID name
--- -------- -------- --------- ---------- ---------- ---------- --------- ----- ----
0 0 Pend 0x2d0 0x104 0x200029bc 0x200027f0 0x0 0xffff Swt_Task
1 31 Ready 0x500 0x44 0x20002f84 0x20002ac8 0x0 0xffff IdleCore000
2 6 Ready 0x1000 0x44 0x20003f94 0x20002fd8 0x0 0xffff TaskSampleEntry1
3 7 Ready 0x1000 0x44 0x20004f9c 0x20003fe0 0x0 0xffff TaskSampleEntry2
4 4 Running 0x200 0xec 0x200051ac 0x20004ff0 0x0 0xffff Example_Exc
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID CPUUSE CPUUSE10s CPUUSE1s TaskEntry name
--- -------- -------- --------- --------- ---------- ---------- --------- ------ ------- --------- -------- ---------- ----
0 0 Pend 0x1000 0xdc 0x2104730c 0x210463e8 0 0xffff 0.0 0.0 0.0 0x2101a199 Swt_Task
1 31 Ready 0x500 0x44 0x210478e4 0x21047428 0 0xffff 0.0 0.0 0.0 0x2101a9c9 IdleCore000
2 5 PendTime 0x6000 0xd4 0x2104e8f4 0x210489c8 0 0xffff 5.7 5.7 0.0 0x21016149 tcpip_thread
3 3 Pend 0x1000 0x488 0x2104f90c 0x2104e9e8 0x1 0xffff 8.6 8.6 0.0 0x21016db5 ShellTaskEntry
4 25 Ready 0x4000 0x460 0x21053964 0x2104f9f0 0 0xffff 9.0 8.9 0.0 0x2101c765 IT_TST_INI
5 4 Running 0x1000 0x458 0x210549bc 0x21053a00 0 0xffff 76.5 76.6 0.0 0x2101c685 Example_Exc
OS exception NVIC dump:
interrupt enable register, base address: 0xe000e100, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x2001 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt pending register, base address: 0xe000e200, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt active register, base address: 0xe000e300, size: 0x20
......@@ -201,13 +194,15 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
interrupt exception register, base address: 0xe000ed18, size: 0xc
0x0 0x0 0xf0f00000
interrupt shcsr register, base address: 0xe000ed24, size: 0x4
0x70008
0x70002
interrupt control register, base address: 0xe000ed04, size: 0x4
0x400f806
0x1000e805
memory pools check:
system heap memcheck over, all passed!
memory pool check end!
根据实际运行环境,上文中的数据会有差异,非固定结果
```
......@@ -215,6 +210,8 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
异常接管一般的定位步骤如下:
0. 确认编译时关掉优化选项,否则下述的描述内容可能被优化掉。
1. 打开编译后生成的镜像反汇编(asm)文件。如果默认没有生成,可以使用objdump工具生成,命令为:
```
......@@ -222,54 +219,59 @@ OpenHarmony LiteOS-M内核的回溯栈模块提供下面几种功能,接口详
```
1. 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。
PC地址指向发生异常时程序正在执行的指令。在当前执行的二进制文件对应的asm文件中,查找PC值0x80037da,找到当前CPU正在执行的指令行,反汇编如下所示:
PC地址指向发生异常时程序正在执行的指令。在当前执行的二进制文件对应的asm文件中,查找PC值0x2101c61a,找到当前CPU正在执行的指令行,反汇编如下所示:
```
UINT32 Get_Result_Exception_0(UINT16 dividend){
80037c8: b480 push {r7}
80037ca: b085 sub sp, #20
80037cc: af00 add r7, sp, #0
80037ce: 4603 mov r3, r0
80037d0: 80fb strh r3, [r7, #6]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:10
UINT32 divisor = 0;
80037d2: 2300 movs r3, #0
80037d4: 60fb str r3, [r7, #12]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:11
UINT32 result = dividend / divisor;
80037d6: 88fa ldrh r2, [r7, #6]
80037d8: 68fb ldr r3, [r7, #12]
80037da: fbb2 f3f3 udiv r3, r2, r3
80037de: 60bb str r3, [r7, #8]
2101c60c <GetResultException0>:
2101c60c: b580 push {r7, lr}
2101c60e: b084 sub sp, #16
2101c610: af00 add r7, sp, #0
2101c612: 4603 mov r3, r0
2101c614: 80fb strh r3, [r7, #6]
2101c616: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff
2101c61a: 681b ldr r3, [r3, #0]
2101c61c: 60fb str r3, [r7, #12]
2101c61e: 68f9 ldr r1, [r7, #12]
2101c620: 4803 ldr r0, [pc, #12] ; (2101c630 <GetResultException0+0x24>)
2101c622: f001 f92b bl 2101d87c <printf>
2101c626: 68fb ldr r3, [r7, #12]
2101c628: 4618 mov r0, r3
2101c62a: 3710 adds r7, #16
2101c62c: 46bd mov sp, r7
2101c62e: bd80 pop {r7, pc}
2101c630: 21025f90 .word 0x21025f90
```
1. 可以看到:
1. 异常时CPU正在执行的指令是udiv r3, r2, r3,其中r3取值为0,导致发生除零异常。
2. 异常发生在函数Get_Result_Exception_0中。
1. 异常时CPU正在执行的指令是ldr r3, [r3, #0],其中r3取值为0xffffffff,导致发生非法地址异常。
2. 异常发生在函数GetResultException0中。
2. 根据LR值查找异常函数的父函数。
包含LR值0x80037fe的反汇编如下所示:
包含LR值0x2101c64d的反汇编如下所示:
```
080037ec <Get_Result_Exception_1>:
Get_Result_Exception_1():
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:15
UINT32 Get_Result_Exception_1(UINT16 dividend){
80037ec: b580 push {r7, lr}
80037ee: b082 sub sp, #8
80037f0: af00 add r7, sp, #0
80037f2: 4603 mov r3, r0
80037f4: 80fb strh r3, [r7, #6]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:16
return Get_Result_Exception_0(dividend);
80037f6: 88fb ldrh r3, [r7, #6]
80037f8: 4618 mov r0, r3
80037fa: f7ff ffe5 bl 80037c8 <Get_Result_Exception_0>
80037fe: 4603 mov r3, r0
2101c634 <GetResultException1>:
2101c634: b580 push {r7, lr}
2101c636: b082 sub sp, #8
2101c638: af00 add r7, sp, #0
2101c63a: 4603 mov r3, r0
2101c63c: 80fb strh r3, [r7, #6]
2101c63e: 4806 ldr r0, [pc, #24] ; (2101c658 <GetResultException1+0x24>)
2101c640: f001 f91c bl 2101d87c <printf>
2101c644: 88fb ldrh r3, [r7, #6]
2101c646: 4618 mov r0, r3
2101c648: f7ff ffe0 bl 2101c60c <GetResultException0>
2101c64c: 4603 mov r3, r0
2101c64e: 4618 mov r0, r3
2101c650: 3708 adds r7, #8
2101c652: 46bd mov sp, r7
2101c654: bd80 pop {r7, pc}
2101c656: bf00 nop
2101c658: 21025fb0 .word 0x21025fb0
```
1. LR值80037fe上一行是bl 80037c8 &lt;Get_Result_Exception_0&gt;,此处调用了异常函数,调用异常函数的父函数为Get_Result_Exception_1()
1. LR值2101c648上一行是bl 2101c60c <GetResultException0&gt;,此处调用了异常函数,调用异常函数的父函数为GetResultException1
2. 重复步骤3,解析异常信息中backtrace start至backtrace end之间的LR值,得到调用产生异常的函数调用栈关系,找到异常原因。
......@@ -3,7 +3,7 @@
## 基本概念
LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double Free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
LMS(Lite Memory Sanitizer)是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能:
......@@ -51,7 +51,7 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
开启LMS调测的典型流程如下:
1. 配置LMS模块相关宏。
配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_m目录下执行 make update_config命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES
配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_m目录下执行 make menuconfig命令配置"Kernel-&gt;Enable Lite Memory Sanitizer"中打开YES(如果没有这个选项,需要先勾选Enable Backtrace)
| 宏 | menuconfig选项 | 含义 | 取值 |
| -------- | -------- | -------- | -------- |
......@@ -104,6 +104,10 @@ OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信
实例代码如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数Example_Lms_test。
请按上文避免编译器优化一节内容,修改osTest.c对应的 ./kernel/liteos_m/testsuites/BUILD.gn。
```
#define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20
......@@ -162,65 +166,114 @@ UINT32 Example_Lms_test(VOID){
### 结果验证
输出结果如下
输出结果示例如下 (根据实际运行环境,数据会有差异)
```
######LmsTestOsmallocOverflow start ######
[ERR]* Kernel Address Sanitizer Error Detected Start *
[ERR]Heap buffer overflow error detected
[ERR]Illegal READ address at: [0x4157a3c8]
[ERR]Shadow memory address: [0x4157be3c : 4] Shadow memory value: [2]
OsBackTrace fp = 0x402c0f88
runTask->taskName = LmsTestCaseTask
runTask->taskID = 2
***backtrace begin***
traceback fp fixed, trace using fp = 0x402c0fd0
traceback 0 -- lr = 0x400655a4 fp = 0x402c0ff8
traceback 1 -- lr = 0x40065754 fp = 0x402c1010
traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038
traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca
[LMS] Dump info around address [0x4157a3c8]:
[0x4157a3a0]: 00 00 00 00 00 00 00 00 | [0x4157be3a | 0]: 1 1
[0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
[0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0
[0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
[0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0
[0x4157a3c8]: [ba] dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: [2] 2
[0x4157a3d0]: 2c 1a 00 00 00 00 00 00 | [0x4157be3d | 0]: 2 3
[0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3
[0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3
[0x4157a3e8]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 4]: 3 3
[0x4157a3f0]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 0]: 3 3
[ERR]* Kernel Address Sanitizer Error Detected End *
str[20]=0xffffffba
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected Start *****
[ERR][TestLmsTsk]Heap buffer overflow error detected
[ERR][TestLmsTsk]Illegal READ address at: [0x21040414]
[ERR][TestLmsTsk]Shadow memory address: [0x21041e84 : 6] Shadow memory value: [2]
psp, start = 21057d88, end = 21057e80
taskName = TestLmsTsk
taskID = 5
----- traceback start -----
traceback 0 -- lr = 0x210099f4
traceback 1 -- lr = 0x2101da6e
traceback 2 -- lr = 0x2101db38
traceback 3 -- lr = 0x2101c494
----- traceback end -----
[LMS] Dump info around address [0x21040414]:
[0x21040390]: 00 00 00 00 00 00 00 00 | [0x21041e7c | 4]: 1 1
[0x21040398]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 0]: 1 1
[0x210403a0]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 4]: 1 1
[0x210403a8]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 0]: 1 1
[0x210403b0]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 4]: 1 1
[0x210403b8]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 0]: 1 1
[0x210403c0]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 4]: 1 1
[0x210403c8]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 0]: 1 1
[0x210403d0]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 4]: 1 1
[0x210403d8]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 0]: 1 1
[0x210403e0]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 4]: 1 1
[0x210403e8]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 0]: 1 1
[0x210403f0]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 4]: 1 1
[0x210403f8]: 40 1e 04 21 05 07 00 80 | [0x21041e83 | 0]: 2 2
[0x21040400]: 00 00 00 00 00 00 00 00 | [0x21041e83 | 4]: 0 0
[0x21040408]: 00 00 00 00 00 00 00 00 | [0x21041e84 | 0]: 0 0
[0x21040410]: 00 00 00 00 [f8] 03 04 21 | [0x21041e84 | 4]: 0 [2]
[0x21040418]: 00 8b 06 00 00 00 00 00 | [0x21041e85 | 0]: 2 3
[0x21040420]: 00 00 00 00 00 00 00 00 | [0x21041e85 | 4]: 3 3
[0x21040428]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 0]: 3 3
[0x21040430]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 4]: 3 3
[0x21040438]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 0]: 3 3
[0x21040440]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 4]: 3 3
[0x21040448]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 0]: 3 3
[0x21040450]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 4]: 3 3
[0x21040458]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 0]: 3 3
[0x21040460]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 4]: 3 3
[0x21040468]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 0]: 3 3
[0x21040470]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 4]: 3 3
[0x21040478]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 0]: 3 3
[0x21040480]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 4]: 3 3
[0x21040488]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 0]: 3 3
[0x21040490]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 4]: 3 3
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected End *****
str[20]=0xfffffff8
######LmsTestOsmallocOverflow stop ######
###### LmsTestUseAfterFree start ######
[ERR]* Kernel Address Sanitizer Error Detected Start *
[ERR]Use after free error detected
[ERR]Illegal READ address at: [0x4157a3d4]
[ERR]Shadow memory address: [0x4157be3d : 2] Shadow memory value: [3]
OsBackTrace fp = 0x402c0f90
runTask->taskName = LmsTestCaseTask
runTask->taskID = 2
***backtrace begin***
traceback fp fixed, trace using fp = 0x402c0fd8
traceback 0 -- lr = 0x40065680 fp = 0x402c0ff8
traceback 1 -- lr = 0x40065758 fp = 0x402c1010
traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038
traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca
[LMS] Dump info around address [0x4157a3d4]:
[0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
[0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0
[0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
[0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0
[0x4157a3c8]: ba dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: 2 2
[0x4157a3d0]: 2c 1a 00 00 [00] 00 00 00 | [0x4157be3d | 0]: 2 [3]
[0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3
[0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3
[0x4157a3e8]: ba dc cd ab c8 a3 57 41 | [0x4157be3e | 4]: 2 2
[0x4157a3f0]: 0c 1a 00 00 00 00 00 00 | [0x4157be3f | 0]: 2 3
[0x4157a3f8]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 4]: 3 3
[ERR]* Kernel Address Sanitizer Error Detected End *
######LmsTestUseAfterFree start ######
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected Start *****
[ERR][TestLmsTsk]Use after free error detected
[ERR][TestLmsTsk]Illegal READ address at: [0x2104041c]
[ERR][TestLmsTsk]Shadow memory address: [0x21041e85 : 2] Shadow memory value: [3]
psp, start = 21057d90, end = 21057e80
taskName = TestLmsTsk
taskID = 5
----- traceback start -----
traceback 0 -- lr = 0x210099f4
traceback 1 -- lr = 0x2101daec
traceback 2 -- lr = 0x2101db3c
traceback 3 -- lr = 0x2101c494
----- traceback end -----
[LMS] Dump info around address [0x2104041c]:
[0x21040398]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 0]: 1 1
[0x210403a0]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 4]: 1 1
[0x210403a8]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 0]: 1 1
[0x210403b0]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 4]: 1 1
[0x210403b8]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 0]: 1 1
[0x210403c0]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 4]: 1 1
[0x210403c8]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 0]: 1 1
[0x210403d0]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 4]: 1 1
[0x210403d8]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 0]: 1 1
[0x210403e0]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 4]: 1 1
[0x210403e8]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 0]: 1 1
[0x210403f0]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 4]: 1 1
[0x210403f8]: 40 1e 04 21 05 07 00 80 | [0x21041e83 | 0]: 2 2
[0x21040400]: 00 00 00 00 00 00 00 00 | [0x21041e83 | 4]: 0 0
[0x21040408]: 00 00 00 00 00 00 00 00 | [0x21041e84 | 0]: 0 0
[0x21040410]: 00 00 00 00 f8 03 04 21 | [0x21041e84 | 4]: 0 2
[0x21040418]: 05 8b 06 00 [00] 00 00 00 | [0x21041e85 | 0]: 2 [3]
[0x21040420]: 00 00 00 00 00 00 00 00 | [0x21041e85 | 4]: 3 3
[0x21040428]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 0]: 3 3
[0x21040430]: 14 04 04 21 00 84 06 00 | [0x21041e86 | 4]: 2 2
[0x21040438]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 0]: 3 3
[0x21040440]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 4]: 3 3
[0x21040448]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 0]: 3 3
[0x21040450]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 4]: 3 3
[0x21040458]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 0]: 3 3
[0x21040460]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 4]: 3 3
[0x21040468]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 0]: 3 3
[0x21040470]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 4]: 3 3
[0x21040478]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 0]: 3 3
[0x21040480]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 4]: 3 3
[0x21040488]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 0]: 3 3
[0x21040490]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 4]: 3 3
[0x21040498]: 00 00 00 00 00 00 00 00 | [0x21041e8d | 0]: 3 3
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected End *****
str[ 0]=0x 0
######LmsTestUseAfterFree stop ######
```
......
......@@ -178,6 +178,8 @@ OpenHarmony LiteOS-M内核的Trace模块提供下面几种功能,接口详细
示例代码如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleTraceTest。
```
#include "los_trace.h"
......@@ -200,9 +202,9 @@ VOID Example_Trace(VOID)
LOS_TraceStop();
LOS_TraceRecordDump(FALSE);
}
UINT32 Example_Trace_test(VOID){
UINT32 ExampleTraceTest(VOID){
UINT32 ret;
TSK_INIT_PARAM_S traceTestTask;
TSK_INIT_PARAM_S traceTestTask = { 0 };
/* 创建用于trace测试的任务 */
memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
......
......@@ -180,6 +180,7 @@
- [异常调测](kernel/kernel-mini-memory-exception.md)
- [Trace调测](kernel/kernel-mini-memory-trace.md)
- [LMS调测](kernel/kernel-mini-memory-lms.md)
- [SHELL](kernel/kernel-mini-debug-shell.md)
- 附录
- [内核编码规范](kernel/kernel-mini-appx-code.md)
- [标准库支持](kernel/kernel-mini-appx-lib.md)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册